背景:我正在使用网络抓取工具来跟踪在线商店的价格。它使用Django。我为每个商店都有一个模块,为每个商店编写了get_price()
和get_product_name()
等函数,这样主模块可以互换使用模块。我有store_a.py,store_b.py,store_c.py等等,每个都定义了这些函数。
为了防止代码重复,我创建了StoreTestCase,它继承自TestCase。对于每个商店,我有一个StoreTestCase的子类,如StoreATestCase和StoreBTestCase。
当我手动测试StoreATestCase 类时,测试运行器会执行我想要的操作。它使用子类self.data
中的数据进行测试,并且不会尝试单独设置和测试父类:
python manage.py test myproject.tests.test_store_a.StoreATest
但是,当我手动测试模块时,例如:
python manage.py test myproject.tests.test_store_a
它首先运行子类的测试并成功,但然后它为父类运行它们并返回以下错误:
for page in self.data:
TypeError: 'NoneType' object is not iterable
store_test.py (父类)
from django.test import TestCase
class StoreTestCase(TestCase):
def setUp(self):
'''This should never execute but it does when I test test_store_a'''
self.data = None
def test_get_price(self):
for page in self.data:
self.assertEqual(store_a.get_price(page['url']), page['expected_price'])
test_store_a.py (子类)
import store_a
from store_test import StoreTestCase
class StoreATestCase(StoreTestCase):
def setUp(self):
self.data = [{'url': 'http://www.foo.com/bar', 'expected_price': 7.99},
{'url': 'http://www.foo.com/baz', 'expected_price': 12.67}]
如何确保Django测试运行器仅测试子类,而不测试父类?
答案 0 :(得分:4)
解决此问题的一种方法是使用Mixins
:
from django.test import TestCase
class StoreTestCase(object):
def setUp(self):
'''This should never execute but it does when I test test_store_a'''
self.data = None
def test_get_price(self):
for page in self.data:
self.assertEqual(store_a.get_price(page['url']), page['expected_price'])
class StoreATestCase(StoreTestCase, TestCase):
def setUp(self):
self.data = [{'url': 'http://www.foo.com/bar', 'expected_price': 7.99},
{'url': 'http://www.foo.com/baz', 'expected_price': 12.67}]
StoreTestCase
不会被执行,因为它不是TestCase
,但您的StoreATestCase
仍然可以从继承中受益。
我认为您的问题发生是因为StoreTestCase
是一个TestCase
实例,所以当您运行测试时它会被执行。
编辑:
我还建议在StoreTestCase.setUp
中引发异常,明确表示没有实现。看看these exception。
你最终会得到这样的东西:
import exceptions # At the top of the file
[...]
def setUp(object):
raise exceptions.NotImplementedError('Please override this method in your subclass')
答案 1 :(得分:0)
您可以将基类隐藏在另一个内部:
store_test.py (父类)
sys.path
test_store_a.py (子类)
import re as re, pandas as pd
from file2 import ClassB as ClassB
from file3 import ClassC as ClassC # ClassC contains static methods that use re
from file4 import ClassD as ClassD
class ClassA(object):
"""Converts dataframe from unicode string objects to Python
string objects, renames column headers.
"""
def __init__(self, dataframe): # dataframe is defined in file4.py in __main__
super(ClassA, self).__init__()
self.df = dataframe.replace({r'[^\x00-\x7F]+':''}, regex=True, inplace=True)
self.df = dataframe.applymap(str)
# I commented out the following and still receive the NameError.
# for headerID in self.df.columns:
# if ('UPC' or 'GTIN1' or 'GTIN' or 'EAN') in headerID:
# header = headerID
# self.df.rename(columns = {'%s'%header:'GTIN1'}, inplace = True)
# if re.search(".MPN", headerID):
# header = headerID
# self.df.rename(columns = {'%s'%header:'MPN'}, inplace = True)
答案 2 :(得分:0)
如果您想避免多重继承,这也是一种可行的解决方案。不能通过 init 构造函数调用Django测试用例,因此必须重写setUp方法:
from unittest import SkipTest
from django.test import TestCase
class BaseTest(TestCase):
def setUp(self):
if self.__class__ == BaseTest:
raise SkipTest('Abstract test')
your_stuff = 'here'
...
唯一的缺点是,跳过的测试将在您的测试报告中提及。 单元测试文档: https://docs.python.org/dev/library/unittest.html#unittest.SkipTest