使用 Junit + Mockito 实践单元测试

发表于:2020-5-14 11:13

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

 作者:Edison Zhou    来源:恰童鞋骚年

#
JUnit
#
Junit
分享:
  一、前言
  相信做过开发的同学,都多多少少写过下面的代码,很长一段时间我一直以为这就是单元测试...
   @SpringBootTest
  @RunWith(SpringRunner.class)
  public class UnitTest1 {
  @Autowired
  private UnitService unitService;
  @Test
  public void test() {
  System.out.println("----------------------");
  System.out.println(unitService.sayHello());
  System.out.println("----------------------");
  }
  }
  但这是单元测试嘛?unitService 中可能还依赖了 Dao 的操作;如果是微服务,可能还要起注册中心。那么这个“单元”也太大了吧!如果把它称为集成测试,可能更恰当一点,那么有没有可能最小粒度进行单元测试嘛?
  单元测试应该是一个带有隔离性的功能测试。在单元测试中,应尽量避免其他类或系统的副作用影响。
  单元测试的目标是一小段代码,例如方法或类。方法或类的外部依赖关系应从单元测试中移除,而改为测试框架创建的 mock 对象来替换依赖对象。
  单元测试一般由开发人员编写,通过验证或断言目标的一些行为或状态来达到测试的目的。
  二、JUnit 框架
  JUnit 是一个测试框架,它使用注解来标识测试方法。JUnit 是 Github 上托管的一个开源项目。
  一个 JUnit 测试指的是一个包含在测试类中的方法,要定义某个方法为测试方法,请使用 @Test 注解标注该方法。该方法执行被测代码,可以使用 JUnit 或另一个 Assert 框架提供的 assert 方法来检查预期结果与实际结果是否一致,这些方法调用通常称为断言或断言语句。
   public class UnitTest2 {
  @Test
  public void test() {
  String sayHello = "Hello World";
  Assert.assertEquals("Hello World", sayHello);
  }
  }
  以下是一些常用的 JUnit 注解:
  以下是一些常用的 Assert 断言:
  三、Mockito 框架
  从上面的介绍我们可以认识到,如何减少对外部的依赖才是实践单元测试的关键。而这正是 Mockito 的使命,Mockito 是一个流行的 mock 框架,可以与 JUnit 结合使用,Mockito 允许我们创建和配置 mock 对象,使用 Mockito 将大大简化了具有外部依赖项的类的测试开发。spring-boot-starter-test 中默认集成了 Mockito,不需要额外引入。
  在测试中使用 Mockito,通常会:
  mock 外部依赖关系并将 mock 对象插入待测代码
  执行被测代码
  验证代码是否正确执行
  3.1 使用 Mockito 创建 mock 对象
  Mockit o提供了几种创建 mock 对象的方法:
  使用静态 mock() 方法
  使用 @Mock 注解
  如果使用 @Mock 注解,则必须触发创建带有 @Mock 注解的对象。使用 MockitoRule 可以做到,它通过调用静态方法 MockitoAnnotations.initMocks(this) 来填充带 @Mock 注解的字段。或者可以使用 @RunWith(MockitoJUnitRunner.class)。
   public class UnitTest3 {
  // 触发创建带有 @Mock 注解的对象
  @Rule public MockitoRule mockitoRule = MockitoJUnit.rule();
  // 1. 使用 @Mock 注解创建 mock 对象
  @Mock private UnitDao unitDao;
  @Test
  public void test() {
  // 2. 使用静态 mock() 方法创建 mock 对象
  Iterator iterator = mock(Iterator.class);
  // when...thenReturn / doReturn...when 模拟依赖调用
  when(iterator.next()).thenReturn("hello");
  doReturn(1).when(unitDao).delete(anyLong());
  // 断言
  Assert.assertEquals("hello", iterator.next());
  Assert.assertEquals(new Integer(1), unitDao.delete(1L));
  }
  }
  3.2 使用 mock 对象实践单元测试
  我们要单元测试的内容,常常包含着对数据库的访问等等,那么我们要如何 mock 掉这部分调用呢?我们可以使用 @InjectMocks 注解创建实例并使用 mock 对象进行依赖注入。
   @Service
  public class UnitServiceImpl implements UnitService {
  @Autowired
  private UnitDao unitDao;
  @Override
  public String sayHello() {
  Integer delete = unitDao.delete(1L);
  System.out.println(delete);
  return "hello unit";
  }
  }

   @RunWith(MockitoJUnitRunner.class)
  public class UnitTest2 {
  @Mock
  private UnitDao unitDao;
  @InjectMocks
  private UnitServiceImpl unitService;
  @Test
  public void unitTest() {
  // mock 调用
  when(unitDao.delete(anyLong())).thenReturn(1);
  Assert.assertEquals("hello unit", unitService.sayHello());
  }
  }
   Mockito 还有很多有趣的实践,比如:@Spy或spy()方法、verify()验证等等,鉴于篇幅原因,读者可自行挖掘。
  3.3 使用 PowerMock mock 静态方法。
  Mockito 也有一些局限性。例如:不能 mock 静态方法和私有方法。有关详细信息,请参阅 Mockito限制的常见问题解答。这个时候我们就要用到 PowerMock,PowerMock 支持 JUnit 和 TestNG,扩展了 EasyMock 和 Mockito 框架,增加了mock static、final 方法的功能。
  首先需要引入 PowerMock 的依赖:
   <!-- PowerMock -->
  <dependency>
  <groupId>org.powermock</groupId>
  <artifactId>powermock-module-junit4</artifactId>
  <version>2.0.7</version>
  <scope>test</scope>
  </dependency>
  <dependency>
  <groupId>org.powermock</groupId>
  <artifactId>powermock-api-mockito2</artifactId>
  <version>2.0.7</version>
  </dependency>
  接下来就能愉快的 mock 静态方法了。
   @RunWith(PowerMockRunner.class)
  @PrepareForTest({StringUtils.class})
  public class UnitTest4 {
  @Test
  public void test() {
  mockStatic(StringUtils.class);
  when(StringUtils.getFilename(anyString())).thenReturn("localhost");
  Assert.assertEquals("localhost", StringUtils.getFilename(""));
  }
  }

      本文内容不用于商业目的,如涉及知识产权问题,请权利人联系博为峰小编(021-64471599-8017),我们将立即处理
《2023软件测试行业现状调查报告》独家发布~

关注51Testing

联系我们

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

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

沪ICP备05003035号

沪公网安备 31010102002173号