子类化TestCase时,如何防止Django在父类上运行单元测试?

Ste*_*art 3 python django unit-testing

背景:我正在研究一个网络抓取工具,以跟踪在线商店的价格。它使用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
Run Code Online (Sandbox Code Playgroud)

但是,当我手动测试模块时,例如:

python manage.py test myproject.tests.test_store_a
Run Code Online (Sandbox Code Playgroud)

它首先为子类运行测试并成功,但是随后为父类运行测试并返回以下错误:

    for page in self.data:
TypeError: 'NoneType' object is not iterable
Run Code Online (Sandbox Code Playgroud)

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'])
Run Code Online (Sandbox Code Playgroud)

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}]
Run Code Online (Sandbox Code Playgroud)

如何确保Django测试运行器仅测试子类,而不测试父类?

Pac*_*aco 5

解决此问题的一种方法是使用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}]
Run Code Online (Sandbox Code Playgroud)

由于StoreTestCase它将不是,因此将不会执行TestCase,但是您StoreATestCase仍将从继承中受益。

我认为您的问题之所以发生是因为它StoreTestCase是一个TestCase实例,因此在您运行测试时便会执行它。

编辑:

我也建议在中提出一个例外StoreTestCase.setUp,明确指出未实现。看看这些异常。您最终将得到如下结果:

import exceptions  # At the top of the file

[...]

def setUp(object):
    raise exceptions.NotImplementedError('Please override this method in your subclass')
Run Code Online (Sandbox Code Playgroud)

  • 在 StoreTestCase(object) 上执行 self.assertEqual() 不是无效的,因为它没有那个方法吗? (2认同)

Sym*_*mon 5

您可以将基类隐藏在另一个基类中:

store_test.py(父类)

from django.test import TestCase

class TestHelpers(object):
    class StoreTestCase(TestCase):
    ...
Run Code Online (Sandbox Code Playgroud)

test_store_a.py(子类)

import store_a
from store_test import TestHelpers

class StoreATestCase(TestHelpers.StoreTestCase):
    ...
Run Code Online (Sandbox Code Playgroud)