从父级继承单元测试 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 .
我想编写一些测试,以便对从父级继承的所有 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 .