JAVA语言

Mockito介绍

Fils de discussió [ Anterior | Següent ]
Mockito介绍
mockito powermock junit 单元测试
Resposta
31/01/17 11:08
# 资源
Mockito官网:http://site.mockito.org/
 
 
# 说明
Mock技术一般用在单元测试中。
Java领域最常见的mock框架为 PowerMock+Mockito 与 JMockit,本文介绍前者。
Mockito 的API是最优雅最简洁的,但是Mockito有个缺陷,它不能mock静态方法和私有方法。尽管正确设计的类与单元测试不应该遇到这种问题,但是现实世界往往是复杂的,有时不得不mock静态方法和私有方法,这时,PowerMock框架就可以大展拳脚了。
JMockit 理论上功能集大于PowerMock+Mockito,但是架不住用的人少,学习曲线较陡,所以还是推荐前者。
 
# 版本选择
 
目前PowerMock不支持新版本的 Mockito,如果项目确定不用PowerMock,可以选择高版本Mockito,否则,选择Mockito版本时必须考虑PowerMock能否支持该版本
PowerMock同时还与JUnit版本有关
 
本例实现时采用的版本为
        <dependency>
            <groupId>org.powermock</groupId>
            <artifactId>powermock-module-junit4</artifactId>
            <version>1.6.5</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.powermock</groupId>
            <artifactId>powermock-api-mockito</artifactId>
            <version>1.6.5</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.mockito</groupId>
            <artifactId>mockito-core</artifactId>
            <version>1.10.19</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>
 
具体参考链接:
 
 
# 示例项目
AssetService 类提供资产相关的API,例如 totalAssetPrice 方法用于计算指定 user 的总资产。资产数据是通过 AssetDao 从数据库中获取的。我们要测试计算个人总资产的代码是否正确,如果此时数据库不可用,该怎么办呢?
AssetServiceBasicTest 类提供了3种解决方案。
第一种方案,我们直接 mock 出一个 AssetDao,通过 when(dao.listAssets("user01")).thenReturn(user01assets) 告诉 mock 对象,当调用 listAssets方法并且入參为 user01 时,返回预先设定好的 user01assets 对象。
第二种方案,我们直接 mock 出一个 AssetService 对象,通过 when(service.totalAssetPrice(anyString())).thenCallRealMethod() 保证在调用 totalAssetPrice 方法时会去调用真实的方法(作为对比,mock出来的对象如果没有通过 when...then... 特别指定函数的期望行为,则函数调用的返回都是系统默认值(int 为0,对象为null))。
第三种方案,我们使用 spy 来模拟出一个 AssetService 对象(注意对象是 new 出来的,spy的特点是默认会执行真实方法,除非特别指定函数的期望行为。要特别注意的是,spy 必须用 do...when... 这种形式来指定函数的期望行为,例如 doReturn(user01assets).when(spy).listAssets("user01")否则真实方法依然会被调用
 
第二、第三种方案都是部分模拟方案(partial mock),Mockito 官方推荐第二种方案
 
 

2. 使用注解

以上三种方案的注解实现分别对应 AssetServiceAnnotationTestWay1,AssetServiceAnnotationTestWay2和AssetServiceAnnotationTestWay3
 
@Mock 注解等同于 mock 方法
@Spy 注解等同于 spy方法
@InjectMocks 注解会自动把其它对象注入到当前对象中(依次尝试构造函数注入、setter方法注入和属性注入)。该注解可以与@Spy同时使用。
 
注意必须通过调用 MockitoAnnotations.initMocks(this) 初始化。
 

3. 使用PowerMock模拟静态类

静态方法 ViolationChecker.isViolation 通过判断资产名称确定资产是否合法。由于需要连接到政府系统,目前无法使用,只能mock
 
AssetServiceStaticTest 类给出了模拟示例。
 
注意两个注解
@RunWith(PowerMockRunner.class)
@PrepareForTest(ViolationChecker.class)
和一行代码
PowerMockito.mockStatic(ViolationChecker.class);
 
 

4. PowerMock与Mockito注解整合

AssetServiceTest 类演示了一个复杂的方法 totalAssetPriceOfAllLegalPerson 的测试是如何写的。所有的数据都是通过 mock 准备的。
 
注意 PowerMock 和 Mockito 注解整合时的一些变化:
  • 不再需要调用 MockitoAnnotations.initMocks(this) 初始化
  • 对应的,AssetService类需要显式的 new 出来
  • 虽然不推荐用 spy 注解,但考虑到便利性,还是使用了 spy注解,因为它可以和 InjectMocks 组合使用
  • AssetService 类并没有 IUserService的 setter 方法,但是自动注入依然成功了,显然是通过属性注入的方式注入的
 
 

5. 从单元测试的层面说

其实上面的测试用例写的并不好,因为在一个方法中测试了太多的内容。更合理的写法参考 AssetServiceTestFinal,每个测试用例只关注当前被测方法本身。
 
 
 
 
 
 
 
 
 
0 (0 Vots)