<p>也许问题不在于如何最好地编写测试docstring,而在于如何编写测试本身?重构测试的方式可以使它们具有自文档性,这会有很长的路要走,并且当代码更改时,docstring不会过时。</p>
<p>为了使测试更加清晰,您可以做一些事情:</p>
<ul>
<li>清晰的描述性测试方法名称(已提及)</li>
<li>测试机构应清晰简洁(自我记录)</li>
<li>在方法上抽象出复杂的设置/拆卸等</li>
<li>更多?</li>
</ul>
<p>例如,如果您有这样的测试:</p>
<pre><code>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
</code></pre>
<p>您可以用方法调用替换setup语句:</p>
<pre><code>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
</code></pre>
<p>请注意,您的测试方法现在由一系列方法调用组成,这些方法调用具有意向性的名称,这是一种特定于您的测试的DSL。这样的测试还需要文档吗?</p>
<p>另一件需要注意的事情是,您的测试方法主要是在一个抽象级别上。阅读测试方法的人会发现算法是:</p>
<ul>
<li>创建小部件</li>
<li>在小部件上调用run</li>
<li>断言代码做了我们期望的事情</li>
</ul>
<p>他们对测试方法的理解并没有被设置小部件的细节所迷惑,小部件是比测试方法低一级的抽象。</p>
<p>测试方法的第一个版本遵循<a href="http://xunitpatterns.com/Inline%20Setup.html" rel="noreferrer">Inline Setup</a>模式。第二个版本遵循<a href="http://xunitpatterns.com/Creation%20Method.html" rel="noreferrer">Creation Method</a>和<a href="http://xunitpatterns.com/Delegated%20Setup.html" rel="noreferrer">Delegated Setup</a>模式。</p>
<p>一般来说,我反对注释,除非它们解释了代码的“原因”。读了鲍勃·马丁叔叔的书,我相信了这一点。有一章是关于评论的,还有一章是关于测试的。我推荐。</p>
<p>有关自动测试最佳实践的更多信息,请查看<a href="http://xunitpatterns.com/" rel="noreferrer">xUnit Patterns</a>。</p>