Java单元测试用例的编写,有什么技巧?(二)

发表于:2021-5-08 09:12

字体: | 上一篇 | 下一篇 | 我要投稿

 作者:阿里技术    来源:知乎

分享:
  4. when语句
  4.1. when().thenReturn()模式
  声明:
  PowerMockito.when(mockObject.someMethod(someArgs)).thenReturn(expectedValue);PowerMockito.when(mockObject.someMethod(someArgs)).thenThrow(expectedThrowable);PowerMockito.when(mockObject.someMethod(someArgs)).thenAnswer(expectedAnswer);PowerMockito.when(mockObject.someMethod(someArgs)).thenCallRealMethod();
  用途:
  用于模拟对象方法,先执行原始方法,再返回期望的值、异常、应答,或调用真实的方法。
  4.1.1. 返回期望值
  public class ListTest {
      @Test
      public void testGet() {
          int index = 0;
          Integer expected = 100;
          List<Integer> mockList = PowerMockito.mock(List.class);
          PowerMockito.when(mockList.get(index)).thenReturn(expected);
          Integer actual = mockList.get(index);
          Assert.assertEquals("返回值不相等", expected, actual);
      }
  }
  4.1.2. 返回期望异常
  public class ListTest {
      @Test(expected = IndexOutOfBoundsException.class)
      public void testGet() {
          int index = -1;
          Integer expected = 100;
          List<Integer> mockList = PowerMockito.mock(List.class);
          PowerMockito.when(mockList.get(index)).thenThrow(new IndexOutOfBoundsException());
          Integer actual = mockList.get(index);
          Assert.assertEquals("返回值不相等", expected, actual);
      }
  }
  4.1.3. 返回期望应答
  public class ListTest {
      @Test
      public void testGet() {
          int index = 1;
          Integer expected = 100;
          List<Integer> mockList = PowerMockito.mock(List.class);
          PowerMockito.when(mockList.get(index)).thenAnswer(invocation -> {
              Integer value = invocation.getArgument(0);
              return value * 100;
          });
          Integer actual = mockList.get(index);
          Assert.assertEquals("返回值不相等", expected, actual);
      }
  }
  4.1.4. 调用真实方法
  public class ListTest {
      @Test
      public void testGet() {
          int index = 0;
          Integer expected = 100;
          List<Integer> oldList = new ArrayList<>();
          oldList.add(expected);
          List<Integer> spylist = PowerMockito.spy(oldList);
          PowerMockito.when(spylist.get(index)).thenCallRealMethod();
          Integer actual = spylist.get(index);
          Assert.assertEquals("返回值不相等", expected, actual);
      }
  }
  4.2. doReturn().when()模式
  声明:
  PowerMockito.doReturn(expectedValue).when(mockObject).someMethod(someArgs);PowerMockito.doThrow(expectedThrowable).when(mockObject).someMethod(someArgs);PowerMockito.doAnswer(expectedAnswer).when(mockObject).someMethod(someArgs);PowerMockito.doNothing().when(mockObject).someMethod(someArgs);PowerMockito.doCallRealMethod().when(mockObject).someMethod(someArgs);
  用途:
  用于模拟对象方法,直接返回期望的值、异常、应答,或调用真实的方法,无需执行原始方法。
  注意:
  千万不要使用以下语法:PowerMockito.doReturn(expectedValue).when(mockObject.someMethod(someArgs));PowerMockito.doThrow(expectedThrowable).when(mockObject.someMethod(someArgs));PowerMockito.doAnswer(expectedAnswer).when(mockObject.someMethod(someArgs));PowerMockito.doNothing().when(mockObject.someMethod(someArgs));PowerMockito.doCallRealMethod().when(mockObject.someMethod(someArgs));
  虽然不会出现编译错误,但是在执行时会抛出UnfinishedStubbingException异常。
  4.2.1. 返回期望值
  public class ListTest {
      @Test
      public void testGet() {
          int index = 0;
          Integer expected = 100;
          List<Integer> mockList = PowerMockito.mock(List.class);
          PowerMockito.doReturn(expected).when(mockList).get(index);
          Integer actual = mockList.get(index);
          Assert.assertEquals("返回值不相等", expected, actual);
      }
  }
  4.2.2. 返回期望异常
  public class ListTest {
      @Test(expected = IndexOutOfBoundsException.class)
      public void testGet() {
          int index = -1;
          Integer expected = 100;
          List<Integer> mockList = PowerMockito.mock(List.class);
          PowerMockito.doThrow(new IndexOutOfBoundsException()).when(mockList).get(index);
          Integer actual = mockList.get(index);
          Assert.assertEquals("返回值不相等", expected, actual);
      }
  }
  4.2.3. 返回期望应答
  public class ListTest {
      @Test
      public void testGet() {
          int index = 1;
          Integer expected = 100;
          List<Integer> mockList = PowerMockito.mock(List.class);
          PowerMockito.doAnswer(invocation -> {
              Integer value = invocation.getArgument(0);
              return value * 100;
          }).when(mockList).get(index);
          Integer actual = mockList.get(index);
          Assert.assertEquals("返回值不相等", expected, actual);
      }
  }
  4.2.4. 模拟无返回值
  public class ListTest {
      @Test
      public void testClear() {
          List<Integer> mockList = PowerMockito.mock(List.class);
          PowerMockito.doNothing().when(mockList).clear();
          mockList.clear();
          Mockito.verify(mockList).clear();
      }
  }
  4.2.5. 调用真实方法
  public class ListTest {
      @Test
      public void testGet() {
          int index = 0;
          Integer expected = 100;
          List<Integer> oldList = new ArrayList<>();
          oldList.add(expected);
          List<Integer> spylist = PowerMockito.spy(oldList);
          PowerMockito.doCallRealMethod().when(spylist).get(index);
          Integer actual = spylist.get(index);
          Assert.assertEquals("返回值不相等", expected, actual);
      }
  }
  4.3. 两种模式的主要区别
  两种模式都用于模拟对象方法,在mock实例下使用时,基本上是没有差别的。但是,在spy实例下使用时,when().thenReturn()模式会执行原方法,而doReturn().when()模式不会执行原方法。测试服务类:
  @Slf4j
  @Service
  public class UserService {
      public long getUserCount() {
          log.info("调用获取用户数量方法");
          return 0L;
      }
  }
  使用when().thenReturn()模式:
  @RunWith(PowerMockRunner.class)
  public class UserServiceTest {
      @Test
      public void testGetUserCount() {
          Long expected = 1000L;
          UserService userService = PowerMockito.spy(new UserService());
          PowerMockito.when(userService.getUserCount()).thenReturn(expected);
          Long actual = userService.getUserCount();
          Assert.assertEquals("返回值不相等", expected, actual);
      }
  }
  在测试过程中,将会打印出"调用获取用户数量方法"日志。
  使用doReturn().when()模式:
  @RunWith(PowerMockRunner.class)
  public class UserServiceTest {
      @Test
      public void testGetUserCount() {
          Long expected = 1000L;
          UserService userService = PowerMockito.spy(new UserService());
          PowerMockito.doReturn(expected).when(userService).getUserCount();
          Long actual = userService.getUserCount();
          Assert.assertEquals("返回值不相等", expected, actual);
      }
  }
  在测试过程中,不会打印出"调用获取用户数量方法"日志。
  4.4. whenNew模拟构造方法
  声明:
  PowerMockito.whenNew(MockClass.class).withNoArguments().thenReturn(expectedObject);PowerMockito.whenNew(MockClass.class).withArguments(someArgs).thenReturn(expectedObject);
  用途:
  用于模拟构造方法。
  案例:
  public final class FileUtils {
      public static boolean isFile(String fileName) {
          return new File(fileName).isFile();
      }
  }
  @RunWith(PowerMockRunner.class)
  @PrepareForTest({FileUtils.class})
  public class FileUtilsTest {
      @Test
      public void testIsFile() throws Exception {
          String fileName = "test.txt";
          File file = PowerMockito.mock(File.class);
          PowerMockito.whenNew(File.class).withArguments(fileName).thenReturn(file);
          PowerMockito.when(file.isFile()).thenReturn(true);
          Assert.assertTrue("返回值为假", FileUtils.isFile(fileName));
      }
  }
  注意:需要加上注解@PrepareForTest({FileUtils.class}),否则模拟方法不生效。
  5. 参数匹配器
  在执行单元测试时,有时候并不关心传入的参数的值,可以使用参数匹配器。
  5.1. 参数匹配器(any)
  Mockito提供Mockito.anyInt()、Mockito.anyString、Mockito.any(Class clazz)等来表示任意值。
  public class ListTest {
      @Test
      public void testGet() {
          int index = 1;
          Integer expected = 100;
          List<Integer> mockList = PowerMockito.mock(List.class);
          PowerMockito.when(mockList.get(Mockito.anyInt())).thenReturn(expected);
          Integer actual = mockList.get(index);
          Assert.assertEquals("返回值不相等", expected, actual);
      }
  }
  5.2. 参数匹配器(eq)
  当我们使用参数匹配器时,所有参数都应使用匹配器。 如果要为某一参数指定特定值时,就需要使用Mockito.eq()方法。
  @RunWith(PowerMockRunner.class)
  @PrepareForTest({StringUtils.class})
  public class StringUtilsTest {
      @Test
      public void testStartWith() {
          String string = "abc";
          String prefix = "b";
          boolean expected = true;
          PowerMockito.spy(StringUtils.class);
          PowerMockito.when(StringUtils.startsWith(Mockito.anyString(), Mockito.eq(prefix))).thenReturn(expected);
          boolean actual = StringUtils.startsWith(string, prefix);
          Assert.assertEquals("返回值不相等", expected, actual);
      }
  }
  5.3. 附加匹配器
  Mockito的AdditionalMatchers类提供了一些很少使用的参数匹配器,我们可以进行参数大于(gt)、小于(lt)、大于等于(geq)、小于等于(leq)等比较操作,也可以进行参数与(and)、或(or)、非(not)等逻辑计算等。
  public class ListTest {
      @Test
      public void testGet() {
          int index = 1;
          Integer expected = 100;
          List<Integer> mockList = PowerMockito.mock(List.class);
          PowerMockito.when(mockList.get(AdditionalMatchers.geq(0))).thenReturn(expected);
          PowerMockito.when(mockList.get(AdditionalMatchers.lt(0))).thenThrow(new IndexOutOfBoundsException());
          Integer actual = mockList.get(index);
          Assert.assertEquals("返回值不相等", expected, actual);
      }
  }

      本文内容不用于商业目的,如涉及知识产权问题,请权利人联系51Testing小编(021-64471599-8017),我们将立即处理
7月博客更文活动,赢取精美礼品,还有机会成为签约作者!

关注51Testing

联系我们

快捷面板 站点地图 联系我们 广告服务 关于我们 站长统计

法律顾问:上海漕溪律师事务所 项棋律师
版权所有 上海博为峰软件技术股份有限公司 Copyright©51testing.com 2003-2022, 沪ICP备05003035号
投诉及意见反馈:webmaster@51testing.com; 业务联系:service@51testing.com 021-64471599-8017

沪公网安备 31010102002173号