5

不要把逻辑放在测试用例中!

 2 years ago
source link: https://www.continuousdelivery20.com/blog/tott-dont-put-logic-in/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client
不要把逻辑放在测试用例中!

乔梁 | 2021-02-06

**编程语言给了我们很大的表达能力。**运算符和条件表达式等概念是重要的工具,让我们能够编写程序,处理各种各样的输入。但是,这种灵活性是以增加复杂性为代价的,它们令我们的程序更难理解。

与生产代码不同,测试中的简单性比灵活性更重要。大多数单元测试都验证一个已知的输入是否产生一个已知的输出。测试应该通过直接声明它们的输入和输出,而不是通过计算来得到,从而避免复杂性。否则,测试用例本身主很容易出现测试自己的 bug 。

让我们看一下下面这个简单的例子。一眼看上去,这个测试是正确的,对么?

@Test public void shouldNavigateToPhotosPage() {
  String baseUrl = "http://plus.google.com/";
  Navigator nav = new Navigator(baseUrl);
  nav.goToPhotosPage();
  assertEquals(baseUrl + "/u/0/photos", nav.getCurrentUrl());
}

作者试图通过在变量中存储共享前缀来避免重复。执行单个字符串的拼接,看起来并不太糟糕,但是如果我们此时做“变量内联”的操作,来简化这个测试用例,会怎么样?

@Test public void shouldNavigateToPhotosPage() {
  Navigator nav = new Navigator("http://plus.google.com/");
  nav.goToPhotosPage();
  assertEquals("http://plus.google.com//u/0/photos", nav.getCurrentUrl()); // Oops!
}

在从测试用例中消除了那些不必要的计算之后,错误就显而易见了—— 我们期望 URL 中有两个斜杠!如果生产代码有相同的 bug ,这个测试用例要么失败,要么(甚至更糟)被错误地通过了。

假如,我们并不试图来拼接它们,而是直接表述我们的输入和输出,那么就不会有这个问题存在,本文也不必存在了。

这是一个非常简单的例子-当一个测试用例包含了更更多的操作符运算,或者包含了循环和条件表达式时,就越来越难以确信它是正确的了。

换一种说法,就是,虽然生产代码描述的是“给定输入,计算其输出”的一般策略,但是,测试用例并不是一般策略,而是对输入/输出的一个具体示例,是一个实例化的需求(其中,它的输出可能包括验证与其他类的交互等副作用)。通常,即使计算它所需的通用逻辑非常复杂,我们也应该很容易判断“输入”与“输入”这对搭档是否一一匹配且正确。

例如,我们很难确切地描绘一个 Javascript 函数为给定服务器响应所创建的整个 DOM 。因此,对这样一个函数进行理想的测试,只需与包含预期输出 HTML 的字符串进行比较,就可以了。

当测试用例确实需要它自己的计算逻辑时,那么,你应该确保这种逻辑从测试体中移出,可以放入一个 Helper 函数中,或是一个单独的帮助文件中。由于这种辅助程序可能会变得非常复杂,所以对于这种非寻常的测试辅助程序来说,拥有自己的测试通常是一个好主意。

谷歌TotT:不要把逻辑放在测试用例中!


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK