Test Methods Must Share Nothing

The following text is a partial translation of the original English article, performed by ChatGPT (gpt-3.5-turbo) and this Jekyll plugin:

常量…我之前写过一些关于它们的东西,主要是说它们是一件坏事,如果公开的话。它们减少了重复,但引入了耦合。消除重复的更好方法是通过创建新的类或方法——传统的面向对象编程方法。这似乎是有道理的,在我们的项目中,我看到越来越少的公共常量。在一些项目中,我们根本没有它们。但有一件事仍然困扰着我:单元测试。大多数程序员似乎认为,当静态分析指出同一文件中有太多相似的字面值时,摆脱它们的最好方法是使用私有静态字面值。这是错误的。

单元测试自然会产生大量重复的代码。测试方法包含类似或几乎相同的功能,这几乎是不可避免的。嗯,我们可以使用更多的@Before@BeforeClass功能,但有时是不可能的。我们可能在一个FooTest.java文件中有20个测试方法。在一个”before”中准备所有对象是不可能的。因此,我们必须在我们的测试方法中一次又一次地做某些事情。

让我们来看看我们的Takes Framework中的一个类:VerboseListTest。这是一个单元测试,它有一个问题,我正在试图告诉你。看看那个MSG私有字面值。它首次在setUp()方法中作为对象构造函数的参数使用,然后在几个测试方法中用于检查该对象的行为。让我简化一下那段代码:

这基本上就是VerboseListTest中所发生的事情,这是非常错误的。为什么?因为这个共享的文字常量MSG在这两个测试方法之间引入了一种不自然的耦合。它们没有任何共同之处,因为它们测试的是Foo类的不同行为。但是这个私有常量将它们联系在一起。现在它们某种程度上是相关的。

当我想要修改其中一个测试方法时,我可能需要同时修改另一个方法。比如说,我想要查看doSomethingElse()在封装的消息为空字符串时的行为。我该怎么办?我改变FooTest.MSG常量的值,而这个常量又被另一个测试方法使用。这就是所谓的耦合。而且这是一件坏事。

我们该怎么办?嗯,我们可以在两个测试方法中都使用那个"something"字符串字面量:

如你所见,我摆脱了setUp()方法和私有静态文字常量MSG。现在我们有了什么?代码重复。字符串"something"在测试类中出现了四次。没有任何静态分析器会容忍这种情况。而且,在VerboseListTest中有七个(!)测试方法在使用MSG。因此,我们将会有14个"something"的出现,对吗?是的,没错,这很可能是这个测试用例的作者之一引入常量的原因——为了消除重复。顺便说一下,@Happy-Neko在请求合并#513中做了这个修改,@carlosmiranda审核了代码,而我则批准了这些更改。所以,三个人都犯了/批准了这个错误,包括我自己。

那么,如何避免代码重复,同时又不引入耦合呢?答案是:

这些字面值必须是不同的。当静态分析器在很多地方看到“something”时,它就是这样说的。它质疑我们——为什么它们是相同的?在每个地方都使用“something”真的很重要吗?为什么不能使用不同的字面值?当然我们可以。而且我们应该。

归根结底,每个测试方法必须有自己的一组数据和对象。它们绝不能在测试方法之间共享。测试方法必须始终是独立的,没有任何共同之处。

考虑到这一点,我们可以很容易地得出结论,像setUp()这样的方法或测试类中的任何共享变量都是“邪恶”的。它们不能被使用,也不能存在。我认为它们在JUnit中的发明给Java代码带来了很多伤害。

Translated by ChatGPT gpt-3.5-turbo/42 on 2023-12-15 at 06:26

sixnines availability badge   GitHub stars