有webservice参与的系统的单元测试,最好使用mock object
手头上的一个项目,是以另外一个系统的webservice做为底层基础。
里面大约有50的操作,最终都要调用这些 web service。
大约有200个test case, 跑完一边居然要15~ 30分钟。因为调用一次WS,大约25秒左右。而且随着远程webservice 服务器的性能问题,这个时间还在增加。
程序员感觉很麻烦。因为调试的时候,如果远程 Webservice出了问题,本地也运行不了。
而且从过去的经验来看,这个webservice 不是很稳定。大约有3~ 5% 的出错率(网络原因造成)。很多时候需要跑很多次,才会明确结果。
所以这个项目越到后来,程序员就越不乐意运行单元测试, 草草的改了代码,最多运行一下对应的 model/controller spec, 然后提交。 最近一个月几乎没有跑过全部的webservice. 所以感觉非常麻烦。
另外一个原因, webserivce 的测试不好写。 不想test database那样可以轻易rollback, webservice 上的操作都需要手动的回复。某个 test case 提交一个POST增加测试数据,那么就必须在这个test case运行完之后删掉对应的数据。如果运行顺利还好说,不顺利的话,程序遇到了异常,直接跳过“删除对应数据”这一步,直接跳到下一个。
难于测试的程序就难于开发,所以项目 就越来越难不好做。
所以今天开始,决心引入mock object,最大限度的解决这个问题。
原则就是:
The mock object should also have exactly the same methods(public) that the original object has.
步骤: 视系统而定。有的系统是java,有的是rails, 这个系统是rails/rspec, 所以...
先找到一个最核心的resource(调用远程webservice的文件),然后mock it!~~~
1. 向 spec/support 中增加 一个mock object: mock_device_resource.rb ,(它所模拟的就是 device_resource.rb )
原则上它的接口跟 original object是一样的,不过由于我的程序有点儿复杂,所以我为它们增加了一个新参数: options. 例如:
原始的对象:
# 因为 类名 实际上就是 Constants if ENV['with_real_webservice'] != "true" DeviceResource = MockDeviceResource DifsSettingResource = MockDifsSettingResource ServerSettingResource = MockServerSettingResourceend