Java单元测试及常用语句 | 京东物流技术团队

发表于:2023-10-26 09:54

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

 作者:京东云开发者    来源:稀土掘金

  1 前言
  编写Java单元测试用例,即把一段复杂的代码拆解成一系列简单的单元测试用例,并且无需启动服务,在短时间内测试代码中的处理逻辑。写好Java单元测试用例,其实就是把“复杂问题简单化,建单问题深入化“。在编写的过程中, 我们也可以对自己的代码进行一个二次检查。
  以下是我总结的一些编写单元测试的好处:
  1.测试代码逻辑时,不需要启动整个应用。
  2.单元测试可以覆盖边界值
  3.提高原有代码的复用
  4.可以有效避免代码改动后,对原有逻辑的潜在影响
  2 准备环境
  Mockito是目前最普遍的单元测试模拟框架。Mockito可以模拟应用中依赖的复杂对象,从而把测试对象和依赖对象隔离开。PowerMock为Mockito提供了扩展功能。为模拟静态方法,final类,和私有方法等。我们选择使用以Mockito为主,PowerMock为辅的框架来做单元测试。
  2.1 引入Mockito和PowerMock包,在pom.xml文件中加入以下依赖:
  <properties>
      <powermock.version>2.0.9</powermock.version>
  </properties>
  <dependency>
      <groupId>org.powermock</groupId>
      <artifactId>powermock-core</artifactId>
      <version>${powermock.version}</version>
      <scope>test</scope>
  </dependency>
  <dependency>
      <groupId>org.powermock</groupId>
      <artifactId>powermock-api-mockito2</artifactId>
      <version>${powermock.version}</version>
      <scope>test</scope>
  </dependency>
  <dependency>
      <groupId>org.powermock</groupId>
      <artifactId>powermock-module-junit4</artifactId>
      <version>${powermock.version}</version>
      <scope>test</scope>
  PowerMock目前最新版本为2.0.9【PowerMock链接】由于PowerMock包中已经包含了对应的Mockito和JUnit包,所以无需再单独引入。
  3 一些常用的mock语句
  3.1 模拟指定类的对象实例,用于模拟依赖对象(类成员)
  在Spring中,这些成员对象通过@Autowire,@Resource,@Value等方式注入,可能涉及到环境配置或者依赖第三方接口。在单元测试中,不是我们关注的点,所以可以用mock模拟
  //方法一
  Mockito.mock(OrderInfo.class);
  //方法二
  @Mock
  private OrderInfo orderInfo;
  @Before
  public void setUp(){
  MockitoAnnotations.initMocks(this);
  }
  3.2 定义被测试对象
  把被测试服务类进行实例化
  @InjectMocks
  private OrderServiceImpl orderService;
  3.3 模拟枚举类型/静态方法
  需要把对应的模拟类放在@PrepareForTest中。
  //必须添加@RunWith和@PrepareForTest在类前
  @RunWith(PowerMockRunner.class)
  @PrepareForTest(OrderTypeEnum.class)
  //在@Before中添加枚举mock
  @Before
  public void beforeTest() {
      mockStatic(OrderTypeEnum.class);
  }
  3.4 模拟依赖方法
  在模拟完依赖的参数和返回值后,可以利用Mockito功能,进行依赖方法的模拟。如果模拟对象还有方法调用,则需要模拟这些依赖对象的方法。
  /***
  when.thenReturn 和 doReturn.when是两种实现方式
  只有在使用@Spy时才会有区别
  参考链接:https://www.imooc.com/wenda/detail/594190#id_653606
  ***/
  //模拟枚举的方法调用
  when(OrderTypeEnum.getByValue(anyInt())).thenReturn(100);
  //模拟依赖对象的依赖方法调用
  doReturn(resultInfoDTO).when(orderInfoService).getLastOrderInfo(orderInfoDTO);
  3.5 模拟构造方法
  PowerMock提供了对构造方法的模拟,但是需要把构造方法的类放在@PrepareForTest中
  //必须在@PrepareForTest中添加对应类
  @PrepareForTest({OrderTypeEnum.class, OrderServiceImpl.class})
  whenNew(OrderInfoDTO.class).withNoArguments().thenReturn(orderInfoDTO);
  3.6 验证方法调用次数
  被测方法调用后,一些方法会出现调用多次或根据不同条件进行不同次数的调用。此时,可以根据验证方法调用次数,确定代码的有效性
  verify(orderInfoService,times(1)).getLastOrderInfo(orderInfoDTO);
  3.7 验证返回值
  对于方法调用后的出参,我们会有一定的预期。所以,可以根据校验返回值是否符合预期,确保返回值的正确性
  Assert.assertEquals(result, "123");
  3.8 验证异常对象
  JUnit的@Test注解提供了一个expected属性,可以指定一个期望的异常类型,用于捕获异常并验证其异常类型。【注】:只能验证异常类型,不能验证异常信息。
  @Test(expected = BPLException.class)
  4 单测举例
  下面是一个本地方法的单元测试用例,方法中调用了外部接口,并且其中包含了枚举值的使用。
  源方法即需要单测方法:
  首先,是单元测试时一些必要的初始化:
  4.1 单测场景一(确定接口调用,并返回值正确):
  通过verify方法来确定接口是否调用过,并且只调用过1次。
  通过assert来确认返回值是否满足预期。
  4.2 单测场景二(必要异常是否抛出):
  通过在@Test注解上加入expected属性,测试当接口返回值为空时,是否可以抛出异常。
  5 总结
  编写单元测试在开发中的地位举足轻重。在开发过程中,避免不了优化或重构历史代码。单元测试,在一定程度上可以帮助测试更新后逻辑,以及潜在调用链。另外也分享一些链接,希望可以帮助大家完成从0到1的搭建。
  本文内容不用于商业目的,如涉及知识产权问题,请权利人联系51Testing小编(021-64471599-8017),我们将立即处理
《2023软件测试行业现状调查报告》独家发布~

关注51Testing

联系我们

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

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

沪ICP备05003035号

沪公网安备 31010102002173号