从父级继承单元测试 class

Inherit unit test from parent class

我想编写一些测试,以便对从父级继承的所有 classes 执行。

例如,我的 class 电机有两个专业:

class Motor():

    def run(self, energy):
        pass


class ElectricMotor(Motor):

    def run(self, electric_energy):
        heat = electric_energy * 0.99
        motion = electric_energy * 0.01
        return heat, motion

class DieselMotor(Motor):

    def run(self, diesel_energy):
        heat = diesel_energy * 0.65
        motion = diesel_energy * 0.35
        return heat, motion

然后我有两个适用于各种电机的测试:

class MotorTest(unittest.TestCase):

    def test_energy_should_be_conserved():

        for class_instance in all_motor_child_classes:
            energy=10
            assert sum(class_instance.run(energy))==energy
            energy=20
            assert sum(class_instance.run(energy))==energy

    def test_motors_should_produce_heat():

        for class_instance in all_motor_child_classes:
            energy = 10
            heat, motion=class_instance.run(energy)
            assert heat>0

我正在寻找的是一种执行循环的方法

for class_instance in all_motor_child_classes:

或不同的编程模式以获得相同的结果。

有什么想法吗? 谢谢 里卡多

嗯,这里有两点:首先有一个 Motor child 类 的列表,然后有每个 类.[= 的实例26=]

愚蠢的简单解决方案是在测试用例的 setUp 中维护这些列表:

from motors import ElectricMotor, DieselMotor

class MotorTest(unittest.TestCase):

    _MOTOR_CHILD_CLASSES = [ElectricMotor, DieselMotor]

    def setUp(self):
       self.motor_child_instances = [cls() for cls in self._MOTOR_CHILD_CLASSES]

    def test_energy_should_be_conserved():
        for class_instance in self.motor_child_instances:
            self.assertEqual(sum(class_instance.run(10)), 10)
            # etc

如果你的 Motor sub类 __init__() 期望不同的论点(如果你想要 proper subtyping according to liskov substitution principle 他们不应该这样 - 但是 "practicality beats purity"),您可以将这些参数添加到您的 MOTOR_CHILD_CLASSES 列表中:

   # (cls, args, kw) tuples
    _MOTOR_CHILD_CLASSES = [
       (ElectricMotor, (42,), {"battery":"ioncad"}),
       (DieselMotor, (), {"cylinders":6}),
       ]

并在 setUp():

中使用它们
       self.motor_child_instances = [
           cls(*args, **kw) for cls, args, kw in self._MOTOR_CHILD_CLASSES
       ]

对于更多 "automagic",您可以在 Motor 上使用自定义元类,这样它就可以注册它的子 类 并提供它们的列表,但是这样您就会丢失提供 per-class 参数的能力 - 并且您还将使测试代码的可读性和可预测性大大降低。

现在另一个 - 恕我直言 很多 更好 - 方法是在你的测试中使用继承:定义一个 mixin object 包含所有通用的测试Motor child 类 :

class MotorTestMixin(object):

    # must be combined with a unittest.TestCase that
    # defines `self.instance` as a `Motor` subclass instance

    def test_energy_should_be_conserved(self):
        self.assertEqual(sum(self.instance.run(10)), 10)

    def test_should_produce_heat(self):
        heat, motion = self.instance.run(10)
        self.assertGreater(heat, 0)

然后每个子类有一个 TestCase:

class DieselMotorTest(MotorTestMixin, TestCase):
    def setUp(self):
        self.instance = DieselMotor()


class ElectricMotorTest(MotorTestMixin, TestCase):
    def setUp(self):
        self.instance = ElectricMotor()

这种方法的好处之一(其他的好处是简单、可读性和对失败测试的更好的错误报告——您将立即知道哪个子类失败而无需执行任何特殊操作)是您不需要添加新的 Motor 子类时不必触及现有代码 - 您只需要为其添加一个新的单独的 TestCase -,您甚至可以在不同的模块中这样做,遵循 open/closed principle .