我有一个以迭代方式构建的对象。我想测试每一步。这是一个糟糕的测试功能:
def test_object:
o = object.Object()
o.step1() # in place method
assert(o.step1property)
o.step2() # in place method
assert(o.step2property)
o.step3() # in place method
# ...
因此,在每一步之后,我都会检查对象是否具有应该存在的所需属性。我可以使用yield关键字将其拆分为子测试,例如:
def test_object:
o = object.Object()
yield o.step1
assert(o.step1property)
yield o.step2
# ...
此时您可能会问:为什么不将这些调用放在单独的测试中?如果他们需要先前结果的正确输出,请将其放在.pickle文件中并使其独立。我普遍同意。但是,我有一个用例,它不是很有帮助:假设step1()初始化类,step2()是JSON导出。然后我需要确保即使我在step1()中更改了东西,JSON导出也始终有效。依赖.pickle文件将是危险的,因为它们可能已经过时,并且JSON导出可能会通过,实际上它会因我的最新对象而失败。我可以在两个单独的测试中分离断言并运行step1()
两次(一次在自己的测试中,一次在测试2的设置方法中),但step1()
非常耗时。
这样做的首选方式是什么?有没有办法调用除yield之外的“subtests”,我可以获得这些子测试的返回值吗?在我的情况下,我喜欢拥有JSON字符串,因为我将所有测试结果保存到输出目录,并且我想将字符串传递给write_to_output_dir
函数(如果这是不好的设计,请告诉我!)。
答案 0 :(得分:3)
如果一个类很难像这样测试,那么你很有可能在面向对象的设计中做了一些不太理想的事情。如果你可以节省时间,请查看this tech talk on unit testing。它还涉及好的(如可测试的)OO设计。
基本上,最好让你的单元测试尽可能原子化。此外,您可以模拟不在特定单元测试中测试的无关功能。关注您的示例:您想要独立检查初始化。我认为这是一种工厂。然后你有一个导出到JSON的方法。这可能是您要模拟初始化对象并在此模拟上测试JSON导出的地方。也就是说,JSON导出器可能也应该是一个单独的类,以避免将初始化与操作逻辑混合。重构代码后,您可能会发现测试代码要容易得多。