作者:Jonathan Rockway、Andrew Trenk
原文链接:http://googletesting.blogspot.tw/2013/06/testing-on-toilet-fake-your-way-to.html
在有了多年的博客经验后,你决定使用下博客平台的API。在使用后,你要思考:如何让你的代码可以不用跟服务器进行通讯而直接能工作?
publicvoid deletePostsWithTag(Tag tag) {
for (Post post : blogService.getAllPosts()) {
if (post.getTags().contains(tag)) { blogService.deletePost(post.getId()); }
}
}
伪造(fake)可以解决!伪造是一种轻量级的API实现,其行为像真正的实现,但并不适合于产品的实现。在这个博客服务的案例中,你所关心的是能够获取和删除帖子,而一个真正的博客服务需要一个数据库和支持多个前端的服务器。你不需要对你的测试代码做任何事情,你所需要的只是实现了博客服务的API。你可以用一个简单的内存实现,就可以达到这个目的:
publicclassFakeBlogServiceimplementsBlogService {
privatefinal Set<Post>posts = new HashSet<Post>(); // 在内存中保存帖子
publicvoid addPost(Post post) { posts.add(post); }
publicvoid deletePost(intid) {
for (Post post : posts) {
if (post.getId() == id) { posts.remove(post); return; }
}
thrownew PostNotFoundException("No post with ID " + id);
}
public Set<Post> getAllPosts() { returnposts; }
}
现在,你的测试可以使用伪造(Fake)API替换真正的博客服务,而且这些被测的代码甚至不知道这两者的区别。
当你的测试不能使用真正的实现方式时,伪造这个方法是非常有用的。例如,如果真正的实现太慢(可能启动需要几分钟)或者如果有非确定性因素(当测试运行时,它外部的机器可能不可以使用)。
你不需要很经常去写这个伪造,因为每个伪造应该是由拥有真正实现方法的个人或团队去创建和维护的。如果你正在使用的API没有提供伪造,往往自己去创建一个也很容易:写一个封装器,用来封装部分你不能在测试中使用的代码,并为这个封装器创建一个伪造。记得在尽可能最低的水平下去创建伪造(例子:如果你的测试代码中连接数据库进行操作,比起伪造所有访问数据库的类,我们更应该直接去伪造这个数据库),这种方式下你只要维护少量伪造,而且你的测试将会执行更多系统重要组成部分的代码。
伪造应该有它们自己的测试来确保它们的行为像真正的实现方式(例子:如果真正的实现方法在给予准确输入时抛出一个异常,那这个伪造的实现方式在给出同样的输入时,也应该要抛出异常)。那可以使用下面的方法来确保:编写API公共接口的测试用例,并分别运行这些测试用例来测试真正的实现和伪造实现。
如果你还是不能完全相信,在你所有测试都使用伪造的情况下,你的代码能在生产环境下正常工作。那么你可以编写少量的集成测试,以确保你的代码在真正的实现上也能工作。