Python中的TDD -我们应该测试helper函数吗?



这是Python中出现的一个理论问题,因为我们几乎可以访问任何我们想要访问的内容,即使它被强调为"隐私"。

def main_function():
_helper_function_()
...
_other_helper_function()

使用TDD,您遵循红-绿-重构周期。一个测试现在看起来像这样:

def test_main_function_for_something_only_helper_function_does():
# tedious setup
...
main_function()
assert something

问题是我的main_function有这么多的设置步骤,我决定测试这些特定情况下的辅助函数:

from main_package import _helper_function
def test_helper_function_works_for_this_specific_input():
# no tedious setup
...
_helper_function_(some_input)
assert helper function does exactly something I expect

但这似乎是一个不好的做法。我应该"知道"吗?关于任何内部/辅助函数?

我重构了main函数,通过将部分移到这些辅助函数中使其更具可读性。所以我重写了测试来测试这些较小的部分,并创建了另一个测试,主函数确实调用了它们。这似乎也适得其反。

另一方面,我不喜欢大量的内部/辅助函数没有专门的单元测试,只有主函数的快乐路径的想法。我想,如果我在重构之前覆盖原始功能,我的旧测试就会足够好。

另外,如果主函数崩溃了,这将意味着许多辅助函数的额外测试也会崩溃。

更好的做法是什么?

问题是我的main_function有这么多的设置步骤,我决定测试这些特定情况下的辅助函数

太好了,这正是应该发生的事情(测试"驾驶";您需要将整体分解为更容易测试的小块)。

我应该"知道"吗?关于任何内部/辅助函数?

权衡。

是的,模块的部分意义在于它们提供了信息隐藏,允许您稍后在不影响客户端(包括测试客户端)的情况下更改代码的工作方式。

但是直接测试内部模块也有好处;测试设计变得更简单,与不相关的细节的耦合更少。每个决定对应的测试更少,这意味着当你需要改变其中一个时,爆炸半径更小。

我通常的想法是这样的:我应该知道有可测试的内部模块,我可以知道一个外部模块的行为就像它耦合到一个内部模块,但我不应该知道外部模块耦合到内部模块。

assert X.result(A,B) == Y.sort([C,D,E])

如果你斜视这个,你会发现它暗示X.resultY.sort今天有一些共同的需求,但它并不一定保证X.result调用Y.sort.

所以我重写了测试,以实际测试这些较小的部分,并创建了另一个测试,主函数确实调用了它们。这似乎也适得其反。

A工作,B工作,C工作,现在你在这里写一个测试f(A,B,C)....是啊,世事无常。

TDD的期望结果是"干净的代码可以工作";(Jeffries);事情的真相是,你可以得到干净的代码,而不必编写世界上所有的测试。

测试在最有可能出现错误的代码中是最重要的——我们只是把东西连接在一起的直线代码,从红-绿-重构循环中获得的好处远不如那些有很多条件和分支的代码。

构建软件设计有两种方法:一种方法是使它如此简单,以至于明显没有缺陷

对于"如此简单以至于明显没有缺陷"的代码部分,一套自动化的程序员测试并不是一项伟大的投资。让两个人执行手动评审,并在上面签字。

私有/辅助函数太多往往是缺少抽象的标志。

也许你应该考虑应用"提取类"重构。此重构将解决您的困惑,因为私有成员最终将成为提取类的公共成员。

请不要,我不是建议在这里为每个私有成员创建一个类,而是稍微摆弄一下模型以找到更好的设计。

最新更新