作者:Erik Kuefler
原文链接:http://googletesting.blogspot.tw/2014/07/testing-on-toilet-dont-put-logic-in.html
程序语言给予我们丰富的表达能力。诸如运算符和条件语句之类的方法是能帮我们在编写程序时处理有大范围输入的重要方法。但是这些灵活的运用是以增加复杂度为代价的,使的我们的程序更加难以理解。
与编写代码不同,在测试中,简单比灵活性更重要。大多数的单元测试是用来验证一个已知的简单输入和一个已知的简单输出。可以通过直接说明输入和输出来避免测试变得复杂而不是去计算它们。否则对于测试来说,这很容易发展为他们自身的错误。
一起来看一个简单的例子。这个测试对你来说是正确的吗?
@Test public voidshouldNavigateToPhotosPage() {
String baseUrl = "http://plus.google.com/";
Navigator nav = newNavigator(baseUrl);
nav.goToPhotosPage();
assertEquals(baseUrl + "/u/0/photos", nav.getCurrentUrl());
}
作者使用一个变量来储存一个共享前缀以避免重复。执行一个字符串连接似乎也没什么问题,但是如果我们利用内联变量来简化这个测试会发生什么变化呢?
@Test public voidshouldNavigateToPhotosPage() {
Navigator nav = newNavigator("http://plus.google.com/");
nav.goToPhotosPage();
assertEquals("http://plus.google.com//u/0/photos", nav.getCurrentUrl()); //哎呀!
}
从测试代码里移除不必要的计算后,这个bug就很明显了——有两个斜杠在这个URL地址里!这个测试不仅会失败或者(甚至更糟)错误的通过了当这个开发的代码原来就有同样的bug。如果我们直接规定输入和输出代替去计算处理它们,我们就不会这样错误的编写了。而且这只是一个非常简单的例子——当一个测试加入太多的操作或者包含循环和条件的语句,就会变得更难以确认测试代码是否是正确的。
换一个方式也可以说是:当编写的代码为了计算输出给定输入,测试具体的输入输出实例而描述一个通用的策略(当输出可能会有副作用比如在检验与其他一些类的交互问题的情况下)。通常判断一个输入输出正确与否是很容易的,即使计算所需的逻辑很复杂。例如:在一次服务器响应时,准确描述出用js函数生成的的对象是很难的。所以为了这个函数而进行的理想测试是只能与网页显示的字符串来相比较。
当测试确实需要自己的逻辑,这些逻辑必须脱离测试体,进入实用程序和辅助函数。当这些辅助函数变得相当复杂时,对于任何重要的测试都拥有自身的测试方法也是相当好的。