作者: Andrew Trenk
原文链接:http://googletesting.blogspot.tw/2015/01/testing-on-toilet-prefer-testing-public.html
这个类需要测试吗?
class UserInfoValidator {
public void validate(UserInfo info){
if (info.getDateOfBirth().isInFuture()) { throw new ValidationException());}
}
}
它的方法有一些逻辑,所以对其进行测试可能是个好主意。但是如果它的用户是唯一的呢?
public class UserInfoService {
private UserInfoValidatorvalidator;
public void save(UserInfo info) {
validator.validate(info); // Throw an exception if the value is invalid.
writeToDatabase(info);
}
}
答案是:也许不需要对其进行测试,因为所有的路径可以通过UserInfoService被测试到。主要的区别在于这个类是一个详细的实现父类,而不是一个公共API。
一个公共API可以被任意数量的用户访问,用户可以输入任何的组合传递给它的方法。你要确保这些测试,即确保用户使用这些API时不会看到问题。一个关于公共API的例子,公共API被代码库中不同的类调用(例如:一个服务器端的类被客户端使用)和常见的被使用于整个代码库的工具类。
一个详细的实现类的存在仅仅为了支持公共API并且被非常有限的用户使用(往往是只有一个用户)。这些类有时可以通过使用它们的公共API被间接测试。
测试实现详细的类在很多case中仍然是有用的,比如这个类是复杂的,或者如果这个测试很难写公共API类。当你对它们进行测试时,它们经常不需要测试的像公共API一样深入,因为一些输入可能永远不会被传递到他们的方法中。(上面的代码示例中,如果UserInfoService可以保证UserInfo永远不为null,那么null将不会被当做UserInfoValidator.validate的参数传入,因为它永远不会发生。)
详细的实现类有时被认为是发生在一个单独的类中的私有方法,因为你通常也不想直接测试私有方法。你也可以试着约束实现类的能见度,例如让他们的包私有在java中。
实现测试细节的类会导致一些问题:
-如果你需要经常更新测试,比如改变一个实现细节类的方法签名或者甚至是重构时,代码很难维护。如果只是公共API的测试,就不会存在这个问题。
- 如果你测试一个行为仅通过细节的实现类,你可能会对你的代码有错误的自信,因为相同的代码路径在公共的API下可能无法正常工作。在重构时也要多加小心,如果不是所有的路径都通过公共API测试,它可能难以确保公共API的所有行为。