使用Mockito与Squaretest进行单元测试

发表于:2023-2-28 09:10

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

 作者:一只爱阅读的程序员    来源:博客园

  项目开发过程中,不少公司都要求写单元测试的代码,可以提高代码的质量,并且可以减少出现BUG的概率。
  对于中小型公司来说,对单元测试不做硬性要求,不写最好。因为还是需要一定的工作量,在保证代码质量和性能的前提下,再去考虑单元测试比较合适。有更好,没有也不影响项目的开发进度。自己所在的项目组对于单元测试有要求,并且要求被测试代码的覆盖率达到20%及以上,每次发布版本的时候,变更覆盖率需要达标才能够发版。
  每次写完代码后,基本都会被要求写单元测试的代码,或者是后期补单元测试的代码,总之都得写。
  下面就聊聊自己在项目中是如何写单元测试的,使用的框架是Mockito框架,maven的依赖为:
          <dependency>
              <groupId>org.mockito</groupId>
              <artifactId>mockito-core</artifactId>
              <version>1.10.19</version>
              <scope>test</scope>
          </dependency>
   
          <dependency>
              <groupId>org.springframework.boot</groupId>
              <artifactId>spring-boot-starter-test</artifactId>
          </dependency>
  安装Squaretest插件:
  选择需要进行单元测试的service实现类。
  可以根据需要选择对应的JUnit版本。
  自己使用的配置为
  生成的测试代码示例。
  package applets.nature.service.impl;
   
  import applets.nature.entiry.GiftExchangeEntiry;
  import applets.nature.entiry.GiftInfo;
  import applets.nature.mapper.GiftInfoMapper;
  import applets.user.entiry.UserInfo;
  import applets.user.service.UserService;
  import org.junit.Test;
  import org.junit.runner.RunWith;
  import org.mockito.InjectMocks;
  import org.mockito.Mock;
  import org.mockito.runners.MockitoJUnitRunner;
   
  import java.util.Arrays;
  import java.util.Collections;
  import java.util.List;
   
  import static org.assertj.core.api.Assertions.assertThat;
  import static org.assertj.core.api.Assertions.assertThatThrownBy;
  import static org.mockito.Mockito.when;
   
  @RunWith(MockitoJUnitRunner.class)
  public class GiftHandlerServiceImplTest {
   
      @Mock
      private GiftInfoMapper mockGiftInfoMapper;
      
      @Mock
      private UserService mockUserService;
   
      @InjectMocks
      private GiftHandlerServiceImpl giftHandlerServiceImplUnderTest;
   
      @Test
      public void testSelectGiftList() throws Exception {
          // Setup
          final GiftInfo giftInfo = new GiftInfo();
          giftInfo.setGiftId("giftId");
          giftInfo.setGiftType("giftType");
          giftInfo.setGiftTitle("giftTitle");
          giftInfo.setGiftDescription("giftDescription");
          giftInfo.setGiftFilePath("giftFilePath");
          giftInfo.setNeedLevel(0);
          giftInfo.setCreateTime("createTime");
          giftInfo.setCreateUser("createUser");
          giftInfo.setIsInvalid(0);
          giftInfo.setStatus(0);
          final List<GiftInfo> expectedResult = Arrays.asList(giftInfo);
   
          // Configure GiftInfoMapper.selectGiftList(...).
          final GiftInfo giftInfo1 = new GiftInfo();
          giftInfo1.setGiftId("giftId");
          giftInfo1.setGiftType("giftType");
          giftInfo1.setGiftTitle("giftTitle");
          giftInfo1.setGiftDescription("giftDescription");
          giftInfo1.setGiftFilePath("giftFilePath");
          giftInfo1.setNeedLevel(0);
          giftInfo1.setCreateTime("createTime");
          giftInfo1.setCreateUser("createUser");
          giftInfo1.setIsInvalid(0);
          giftInfo1.setStatus(0);
          final List<GiftInfo> giftInfos = Arrays.asList(giftInfo1);
          when(mockGiftInfoMapper.selectGiftList()).thenReturn(giftInfos);
   
          // Configure UserService.selectUserByOpenid(...).
          final UserInfo userInfo = new UserInfo();
          userInfo.setUserId("userId");
          userInfo.setUserName("userName");
          userInfo.setNickName("nickName");
          userInfo.setOpenid("openid");
          userInfo.setUserPhone("userPhone");
          userInfo.setAvatarUrl("avatarUrl");
          userInfo.setGender(0);
          userInfo.setCreateTime("createTime");
          userInfo.setRegistrationCode("registrationCode");
          userInfo.setUpdateTime("updateTime");
          when(mockUserService.selectUserByOpenid("openid")).thenReturn(userInfo);
   
          when(mockGiftInfoMapper.selectUserExchange("openid")).thenReturn(Arrays.asList(0));
   
          // Run the test
          final List<GiftInfo> result = giftHandlerServiceImplUnderTest.selectGiftList("openid");
   
          // Verify the results
          assertThat(result).isEqualTo(expectedResult);
      }
   
      @Test
      public void testSelectGiftList_GiftInfoMapperSelectGiftListReturnsNoItems() throws Exception {
          // Setup
          when(mockGiftInfoMapper.selectGiftList()).thenReturn(Collections.emptyList());
   
          // Configure UserService.selectUserByOpenid(...).
          final UserInfo userInfo = new UserInfo();
          userInfo.setUserId("userId");
          userInfo.setUserName("userName");
          userInfo.setNickName("nickName");
          userInfo.setOpenid("openid");
          userInfo.setUserPhone("userPhone");
          userInfo.setAvatarUrl("avatarUrl");
          userInfo.setGender(0);
          userInfo.setCreateTime("createTime");
          userInfo.setRegistrationCode("registrationCode");
          userInfo.setUpdateTime("updateTime");
          when(mockUserService.selectUserByOpenid("openid")).thenReturn(userInfo);
   
          when(mockGiftInfoMapper.selectUserExchange("openid")).thenReturn(Arrays.asList(0));
   
          // Run the test
          final List<GiftInfo> result = giftHandlerServiceImplUnderTest.selectGiftList("openid");
   
          // Verify the results
          assertThat(result).isEqualTo(Collections.emptyList());
      }
  }
  生成的代码说明,以查询方法SelectGiftLis为例:如果是测试service接口,一般使用serviceImpl来写测试用例,serviceImpl中一般会引入mapper接口。
  测试代码中一般都是先生成一个对象,传入mapper接口方法的参数中,并且会创建一个mapper接口的返回对象。然后在使用serviceImpl来测试查询方法,mock一个同样的查询参数,serviceImpl查询时就会有返回值。最后比对mapper接口返回的结果和serviceImpl查询返回的结果是否一致。
  一致则通过测试,不一致则测试不通过。
  点击如下图中的执行即可,效果如下:
  有执行不成功的方法,自己在稍微修改一下测试的代码即可。
  再次执行结果全部通过。
  IDAE插件Squaretest是收费的,免费使用时间为30天。个人版本收费价格为35美元,有破解版本的小伙伴可以分享一下。
  完成第一步单元测试,下一步还需要收集测试之后的代码覆盖率。
  添加依赖如下:
  <dependency>
      <groupId>org.jacoco</groupId>
      <artifactId>jacoco-maven-plugin</artifactId>
      <version>0.8.3</version>
  </dependency>
  配置maven plugin 插件:
  <plugin>
          <groupId>org.jacoco</groupId>
          <artifactId>jacoco-maven-plugin</artifactId>
          <version>0.8.3</version>
          <configuration>
            <includes>
              <include>com/**/*</include>
            </includes>
          </configuration>
          <executions>
            <execution>
              <id>pre-test</id>
              <goals>
                <goal>prepare-agent</goal>
              </goals>
            </execution>
            <execution>
              <id>post-test</id>
              <phase>test</phase>
              <goals>
                <goal>report</goal>
              </goals>
            </execution>
          </executions>
        </plugin>
  依次执行clean/compile/test
  遇到问题,没有生成测试报告,也没报错信息。查看控制台信息,发现单元测试被跳过执行。
  修改配置后,继续执行,发现如下信息,Skipping JaCoCo execution due to missing execution data file。
  说是配置文件中配置了argLine 配置项,导致出现问题,去除后重新执行,代码覆盖率生成成功。
  可以点击进入查看每一行代码的覆盖率。绿色的表示测试时已经已经覆盖到该行的代码,粉色的表示未覆盖到。
  至此,单元测试操作,并且生成代码覆盖率完成。
  本文内容不用于商业目的,如涉及知识产权问题,请权利人联系51Testing小编(021-64471599-8017),我们将立即处理
《2023软件测试行业现状调查报告》独家发布~

关注51Testing

联系我们

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

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

沪ICP备05003035号

沪公网安备 31010102002173号