python - 从父类继承单元测试
问题描述
我想以一种对从父类继承的所有类执行的方式编写一些测试。
例如,我有两个专业的电机类:
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
子类的列表,然后有每个这些类的实例。
愚蠢的简单解决方案是在您的测试用例中维护这些列表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
子类__init__()
需要不同的参数(如果您想根据 liskov 替换原则进行正确的子类型化,则它们不应该这样做- 但是,“实用性胜过纯度”),您可以将这些参数添加到您的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
]
对于更“自动”的东西,您可以使用自定义元类,Motor
以便它可以注册其子类并提供它们的列表,但是您将失去提供每个类参数的能力 - 您还将进行测试代码的可读性和可预测性要低得多。
现在另一种 - 恕我直言更好Motor
- 方法是在您的测试中使用继承:定义一个 mixin 对象,其中包含所有子类共有的所有测试:
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——你甚至可以在一个不同的模块中这样做,遵循开放/封闭原则。
推荐阅读
- c# - 如何使我的 fastcolored 文本框透明?
- mysql - MariaDB 上的 MySQL 查询非常慢
- c - 第二个 fget 后的分段错误
- swift - Extension to generic struct where element is generic struct
- python - 比较嵌套字典中的最小值
- javascript - 如何创建定义长度的预填充数组?
- python-3.x - 使用 Python 3.x 如何将特定变量分配为记事本中的字符串
- php - 将 Laravel 转换为 PWA
- forms - 在提交事件中使用 Google App 脚本获取 Google 表单中特定问题/项目的值
- mongodb - 如何获得集合的独特价值