《Java单元测试实战》——案例集锦:Java单元测试典型案例集锦(5) https://developer.aliyun.com/article/1232054?groupCode=java
六、 如何测试链式调用
在日常编码过程中,很多人都喜欢使用链式调用,这样可以让代码变得更简洁。
1. 案例代码
这里,通过修改后的添加跨域支持代码来举例说明(原方法没有返回值)。
2. 方法1:普通测试法(不推荐)
正常情况下,每一个依赖对象及其调用方法都要mock,编写的代码如下:
/** * 跨域辅助测试类 */ public class CorsHelperTest { /** * 测试: 添加跨域支持 */ @Test public void testAddCorsMapping() { // 模拟依赖方法 CorsRegistry registry = Mockito.mock(CorsRegistry.class); CorsRegistration registration = Mockito.mock(CorsRegistration.class); Mockito.doReturn(registration).when(registry).addMapping(Mockito.anyString()); Mockito.doReturn(registration).when(registration).allowedOrigins(Mockito.any()); Mockito.doReturn(registration).when(registration).allowedMethods(Mockito.any()); Mockito.doReturn(registration).when(registration).allowCredentials(Mockito.anyBoolean()); Mockito.doReturn(registration).when(registration).maxAge(Mockito.anyLong()); Mockito.doReturn(registration).when(registration).allowedHeaders(Mockito.any()); // 调用测试方法 Assert.assertEquals("跨域注册不一致", registration, CorsHelper.addCorsMapping(registry)); // 验证依赖方法 Mockito.verify(registry).addMapping("/**"); Mockito.verify(registration).allowedOrigins("*"); Mockito.verify(registration).allowedMethods("GET", "HEAD", "POST", "PUT", "DELETE", "OPTIONS"); Mockito.verify(registration).allowCredentials(true); Mockito.verify(registration).maxAge(3600L); Mockito.verify(registration).allowedHeaders("*"); } }
3. 方法2:利用RETURNS_DEEP_STUBS参数法(推荐)
对于链式调用,Mockito提供了更加简便的单元测试方法——提供Mockito.RETURNS_DEEP_STUBS参数,实现链式调用返回对象的自动mock。利用Mockito.RETURNS_DEEP_STUBS参数编写的测试用例如下:
/** * 跨域辅助测试类 */ public class CorsHelperTest { /** * 测试: 添加跨域支持 */ @Test public void testAddCorsMapping() { // 模拟依赖方法 CorsRegistry registry = Mockito.mock(CorsRegistry.class, Answers.RETURNS_DEEP_STUBS); CorsRegistration registration = Mockito.mock(CorsRegistration.class); Mockito.when(registry.addMapping(Mockito.anyString()) .allowedOrigins(Mockito.any()) .allowedMethods(Mockito.any()) .allowCredentials(Mockito.anyBoolean()) .maxAge(Mockito.anyLong()) .allowedHeaders(Mockito.any())) .thenReturn(registration); // 调用测试方法 Assert.assertEquals("跨域注册不一致", registration, CorsHelper.addCorsMapping(registry)); // 验证依赖方法 Mockito.verify(registry.addMapping("/**") .allowedOrigins("*") .allowedMethods("GET", "HEAD", "POST", "PUT", "DELETE", "OPTIONS") .allowCredentials(true) .maxAge(3600L)) .allowedHeaders("*"); } }
代码说明:
• 在mock对象时,需要指定Mockito.RETURNS_DEEP_STUBS参数;
• 在mock方法时,采用when-then模式,when内容是链式调用,then内容是返回的值;
• 在verify方法时,只需要验证最后1次方法调用,verify内容是前n次链式调用;如果验证时某个方法调用的某个参数指定错误时,最后一个方法调用验证将因为这个mock对象没有方法调用而抛出异常。
4. 方法3:利用RETURNS_SELF参数法(推荐)
对于相同返回值的链式调用,Mockito提供了更加简便的单元测试方法——提供Mockito.RETURNS_SELF参数,实现链式调用返回对象的自动mock,而且还能返回同一mock对象。利用Mockito.RETURNS_SELF参数编写的测试用例如下:
代码说明:
• 在mock对象时,对于自返回对象,需要指定Mockito.RETURNS_SELF参数;
• 在mock方法时,无需对自返回对象进行mock方法,因为框架已经mock方法返回了自身;
• 在verify方法时,可以像普通测试法一样优美地验证所有方法调用。
方法对比:
• 普通测试法:mock调用方法语句较多;
• 利用RETURNS_DEEP_STUBS参数法:mock调用方法语句较少,适合于链式调用返回不同值;
• 利用RETURNS_SELF参数法:mock调用方法语句最少,适合于链式调用返回相同值。
《Java单元测试实战》——案例集锦:Java单元测试典型案例集锦(7) https://developer.aliyun.com/article/1232052?groupCode=java