也许问题不在于如何最好地编写测试文档字符串,而是如何编写测试本身?以自我记录的方式重构测试可以有很长的路要走,并且您的文档字符串在代码更改时不会过时。
您可以做一些事情来使测试更清晰:
- 清晰且描述性的测试方法名称(已提及)
- 测试主体应该清晰简洁(自我记录)
- 抽象出方法中复杂的设置/拆卸等
- 更多?
例如,如果您有这样的测试:
def test_widget_run_returns_0():
widget = Widget(param1, param2, "another param")
widget.set_option(true)
widget.set_temp_dir("/tmp/widget_tmp")
widget.destination_ip = "10.10.10.99"
return_value = widget.run()
assert return_value == 0
assert widget.response == "My expected response"
assert widget.errors == None
您可以将设置语句替换为方法调用:
def test_widget_run_returns_0():
widget = create_basic_widget()
return_value = widget.run()
assert return_value == 0
assert_basic_widget(widget)
def create_basic_widget():
widget = Widget(param1, param2, "another param")
widget.set_option(true)
widget.set_temp_dir("/tmp/widget_tmp")
widget.destination_ip = "10.10.10.99"
return widget
def assert_basic_widget():
assert widget.response == "My expected response"
assert widget.errors == None
请注意,您的测试方法现在由一系列具有意图揭示名称的方法调用组成,这是一种特定于您的测试的 DSL。这样的测试还需要文档吗?
另外需要注意的是,您的测试方法主要处于一个抽象级别。阅读测试方法的人会看到算法是:
- 创建小部件
- 在小部件上调用 run
- 断言代码符合我们的预期
他们对测试方法的理解并没有被设置小部件的细节所混淆,这是比测试方法低一级的抽象。
测试方法的第一个版本遵循Inline Setup 模式。第二个版本遵循Creation Method 和Delegated Setup 模式。
通常我反对 cmets,除非他们解释代码的“原因”。阅读 Bob Martin 叔叔的Clean Code 让我相信了这一点。有一章是关于 cmets 的,还有一章是关于测试的。我推荐它。
有关自动化测试最佳实践的更多信息,请查看xUnit Patterns。