课程章节介绍
同学们,我们接下来讲一个在测试里特别有用的技巧:如何模拟 Web 服务的调用,也就是“打桩”或者叫“Mock”。
大家知道,我们在写单元测试的时候,最怕的就是依赖外部系统,比如要调一个第三方的 Web 服务。如果测试的时候真的去调,不仅慢,还可能花钱,万一对方服务刚好挂了,你的测试也跟着失败,这就不合理了。所以我们希望测试的时候,能假装调了一次 Web 服务,然后直接返回一个我们预先准备好的假响应,这样测试就完全在我们自己的掌控之中。
那 Apex 里怎么做呢?很简单,就三步。
第一步,写一个类,让它实现 `WebServiceMock` 接口。这个接口只有一个方法,叫 `doInvoke`。你就在这个 `doInvoke` 方法里,把你想返回的假数据填进去。比如,不管外面传进来什么请求,你都给一个固定的成功响应。这就相当于你提前把答案写好,等着别人来问的时候直接给出去。
第二步,在你的测试方法里,调用 `Test.setMock`。这个方法需要两个参数。第一个参数是 `WebServiceMock.class`,注意这里就是把接口的类类型传进去,告诉平台“我要模拟的是 Web 服务调用这种类型”。第二个参数,就是你刚才写好的那个实现类的一个新实例,比如 `new MyWebServiceMock()`。这样一来,Apex 运行时就记住了:哦,接下来如果在这个测试里遇到调用 Web 服务的代码,不要真的去联网,而是去问这个 `MyWebServiceMock` 的实例要答案。
第三步,正常写你的测试逻辑。当你被测试的代码里,调用那些 salesforce 内置的 Web 服务方法时,因为我们现在处在测试上下文,Apex 运行时会自动拦截这个调用,转而调用你那个 Mock 类里的 `doInvoke` 方法,把假响应给回去。整个过程完全透明,你的业务代码根本不知道自己其实是在跟一个“替身”说话。
这里要特别注意一个知识点,跟托管包有关系。如果你的 Web 服务调用代码是打包在一个托管包里的,那么你的测试类和 Mock 类也必须放在同一个包里面,并且要有相同的命名空间。只有从同一个包里的测试方法去调用 `Test.setMock`,这种模拟才会生效。如果你试图在包外的测试里去模拟包内的 Web 服务调用,那是不行的。所以,如果是 ISV 在开发托管包,一定要记得在包内写好对应的测试和 Mock 类。
总结一下,今天的内容就是通过 `Test.setMock` 来模拟 Web 服务调用,让我们能写出又快、又稳、又不依赖外部的单元测试。你在 Mock 类里定好假响应,测试里用 `Test.setMock` 注册一下,测试上下文里的 Web 服务调用就全听你的指挥了。大家在实际项目中一定要把这个用起来,会极大提升你的测试质量。好了,这节课就到这儿,下回我们继续拆解更多好用的测试技巧。
关键词
Apex
Salesforce
Developer Guide