给出一些带有一些多重继承和/或混合的类的层次结构(但你可以称之为)。
我为每个基类和mixin都有一个详细的测试用例(unittest.TestCase
)。
如何将这些测试用例重用于从Base类和mixins派生的类?我觉得,测试/断言派生类继承自某些基类并不足以确保它继承基类的特定行为。
我想写一些类似的东西:
class Base(object):
# provides certain behavior
class Derived(Base, Mixin):
# does some additional stuff compared to Base and Mixin
class BaseTest(unittest.TestCase):
# tests on Base's behavior
class DerivedTest(unittest.TestCase):
def setUp(self):
self.default = Derived()
def test_has_behavior_of_base(self):
# instead of
self.assertIsInstance(self.default, Base)
self.assertIsInstance(self.default, Mixin)
# write
self.assertPasses(BaseTest, Derived)
是否有 pythonic 方法可以通过Pythons unittest
模块实现此目的,并且可能对nose
包提供一些帮助?
答案 0 :(得分:1)
一般情况下,由于 Python 是一种 duck-typed 语言,因此最好尽量减少对显式类型/类的检查(至少如果你需要的话)更多 Pythonic 方法。
由于 duck-typing 主要依赖于行为,而 nose 提供了测试的自动检测,如果您使用目录调用它并相应地命名您的测试类和方法(即包含单词 test 等,我建议如下:
为 base 类定义一个测试类,测试基类的所有行为。将公共代码分解为非测试方法,比如baseClassCore
,它调用实际方法,获取结果,然后返回它们。然后为每个派生的类设置一个测试,该类调用baseClassCore
代码并断言预期的结果(如果断言代码对所有这些代码也是通用的,那么也可以将其分解出来并且然后从测试方法调用。)
然后,对于特定的派生的类,为每个仅测试这些类特有的行为的测试类创建一个测试类。
您也可以在派生类测试中针对该特定类型的测试中调用baseClassCore
,而不是 base 类测试 - 它是一个偏好问题。
一旦这些都被定义了(其中许多只是围绕核心代码的包装器,因此它们在 JUnit 结果中被拆分为单独的测试并传递所需的特定类型),运行针对整个目录的 nose 应检测并运行它们。如果使用 -v 标志运行,您将在运行时获取方法名称,或者,如果存在,则获取方法签名下方的文档字符串,而不仅仅是状态字母。
请注意,您无需明确使用 unittest 。如果从unittest.TestCase
派生测试类,那么 nose 就足以获得与 JUnit 兼容的行为。
顺便说一句,如果您有任何需要的配置(截止日期,使用的服务器等), nose-testconfig 非常方便(https://pypi.python.org/pypi/nose-testconfig)。我通常将它与 JSON 文件一起使用,然后将其输入名为dict
的{{1}}。
答案 1 :(得分:0)
这是一个已填写的示例。 Square来自Rectangle。如果我们从TestRectangle派生TestSquare,其中TestRectangle派生自unittest.TestCase,那么TestRectangle的所有测试方法也将从TestSquare运行。
import unittest
class Rectangle(object):
def __init__(self, width, height):
self._width = width
self._height = height
def get_area(self):
return self.get_width() * self.get_height()
def get_width(self):
return self._width
def get_height(self):
return self._height
def set_width(self, width):
self._width = width
def set_height(self, height):
self._height = height
class Square(Rectangle):
def __init__(self, side):
self._side = side
def get_width(self):
return self._side
def set_width(self, width):
self._side = width
def get_height(self):
return self._side
def set_height(self, height):
self._side = height
class TestRectangle(unittest.TestCase):
def setUp(self):
self.default = Rectangle(2, 3)
def test_area(self):
self.assertEqual(
self.default.get_area(),
self.default.get_width() * self.default.get_height())
def test_set_get(self):
self.default.set_width(4)
self.default.set_height(5)
self.assertEqual(self.default.get_width(), 4)
self.assertEqual(self.default.get_height(), 5)
class TestSquare(TestRectangle):
def setUp(self):
self.default = Square(3)