而不是加入
Unittest可能是Python中最著名的测试编写框架。 它非常容易学习,也很容易在您的项目中开始使用。 但是没有什么是完美的。 在本文中,我想谈一谈我个人(我认为不是一个人)在单元测试中缺少的一项功能。
关于单元测试的一点
在讨论(并谴责)测试框架之前,我认为有必要对测试进行一些讨论。 当我第一次听到“单元测试”一词时,我认为某些质量控制服务负责检查软件模块是否符合要求。 当我发现这些相同的测试应该由程序员编写时,请想象一下我的惊讶。 起初我根本没有编写测试……。 当您早上醒来并向用户阅读时,这些感觉都无法替代这些感觉。 迫切需要做些事情。” 最初,在我看来这是一个完全正常的过程,直到我编写了第一个单元测试后才发现错误。 在发现问题之前,单元测试通常似乎毫无用处。 现在,我不能在没有编写测试的情况下提交新功能。
但是测试不仅用于验证代码是否正确编写。 我认为这是执行测试的功能列表:
- 检测程序代码中的错误
- 使程序员相信他们的代码有效
- 上一段的推论:安全修改程序的能力
- 测试-一种最能正确描述系统行为的文档
从某种意义上说,测试重复了程序的结构。 构建程序的原理是否适用于测试? 我相信是的-这是相同的程序,尽管要测试另一个。
问题描述
在某个时候,我有了编写抽象测试的想法。 那是什么意思 这是一个不会自行执行的测试,而是声明依赖于继承程序中定义的参数的方法。 然后我发现我无法在单元测试中做到这一点。 这是一个例子:
class SerializerChecker(TestCase): model = None serializer = None def test_fields_creation(self): props = TestObjectFactory.get_properties_for_model(self.model) obj = TestObjectFactory.create_test_object_for_model(self.model) serialized = self.serializer(obj) self.check_dict(serialized.data, props)
我认为,即使不知道TestObjectFactory的实现和check_dict方法的实现,很明显props是对象的属性字典,而obj是我们要检查序列化器的对象。 check_dict递归地检查字典是否匹配。 我认为许多熟悉unittest的人会立即说该测试不符合我对abstract的定义。 怎么了 因为test_fields_creation方法将从此类执行,所以我们绝对不需要。 经过一些信息搜索,我得出的结论是,最适当的选择不是继承TestCase的SerializerChecker,而是以某种方式实现继承人:
class VehicleSerializerTest(SerializerChecker, RecursiveTestCase): model = Vehicle serializer = VehicleSerialize
RecursiveTestCase是TestCase的后代,它实现了check_dict方法。
这个解决方案在几个方面都很难做到:
- 在SerializerChecker类中,我们需要知道子级必须继承自TestCase。 对于那些不熟悉此代码的人,这种依赖性可能会导致问题。
- 开发环境强地认为我错了,因为SerializerChecker没有check_dict方法
开发环境抛出的错误看来您可以简单地为check_dict添加一个存根,并且所有问题都已解决:
class SerializerChecker: model = None serializer = None def check_dict(self, data, props): raise NotImplementedError def test_fields_creation(self): props = TestObjectFactory.get_properties_for_model(self.model) obj = TestObjectFactory.create_test_object_for_model(self.model) serialized = self.serializer(obj) self.check_dict(serialized.data, props)
但这不是该问题的完整解决方案:
- 实际上,我们创建了一个接口,该接口不是实现此类的后代,而是实现了RecursiveTestCase,它为体系结构创建了合理的问题。
- TestCase有许多assert *方法。 我们真的需要为每个使用过的存根编写一个存根吗? 还是一个不错的解决方案?
总结一下
Unittest没有提供“断开”从TestCase继承的类的理智的能力。 如果将这样的功能添加到框架中,我将非常高兴。 您如何解决这个问题?