近日,项目上要求提升单元测试覆盖率,在补覆盖率过程中,把自己的一些写法分享出来,如果能帮助同样需要补覆盖率的你少走点弯路,那就再好不过了>_<
1.引入依赖
引入Mock依赖
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>1.10.19</version>
<scope>test</scope>
</dependency>
<!-- 视情况引入powermock依赖 -->
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-core</artifactId>
<version>1.6.4</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-module-junit4</artifactId>
<version>1.6.4</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-api-mockito</artifactId>
<version>1.6.4</version>
<scope>test</scope>
</dependency>
引入junit依赖
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
<optional>true</optional>
</dependency>
Mockito和PowerMockito版本对应关系
Mockito | PowerMock
2.0.0-beta - 2.0.42-beta | 1.6.5+
1.10.19 | 1.6.4
1.10.8 - 1.10.x | 1.6.2+
1.9.5-rc1 - 1.9.5 | 1.5.0 - 1.5.6
1.9.0-rc1 & 1.9.0 | 1.4.10 - 1.4.12
1.8.5 | 1.3.9 - 1.4.9
1.8.4 | 1.3.7 & 1.3.8
1.8.3 | 1.3.6
1.8.1 & 1.8.2 | 1.3.5
1.8 | 1.3
1.7 | 1.2.5
2.Mock对象
这里主要使用注解的方式:
@InjectMocks:用于Mock你要测试的类
@Mock:用于注入你要测试的类的变量(可以稍微理解成相当于原来类里的@Resource或者@Autowired)
单元测试的写法:
0.首先写一个MockitoBasedTest类
1.首先在测试方法中首先模拟出该方法的参数;
2.如果有调用其他service的方法,且返回值后续需要判断,则需要模拟该service的方法,用Mockito.when().thenReturn()来进行模拟,模拟时需要自己给返回参数赋值以便通过判断;
如果无返回值,可以用Mockito.doNothing().when()来进行模拟;
3.最后,用你在@InjectMocks下引入的类调用方法完成单元测试;
PS:如果遇到私有变量的情况,可以通过反射的方法来赋值;
如果在测试方法中某一个方法被多次调用,可以在thenReturn()里添加多个返回值来实现依次返回不同的值;
示例代码如下:
@RunWith(SpringJUnit4ClassRunner.class)
@WebAppConfiguration
public abstract class MockitoBasedTest {
@Before
public void setUp() throws Exception {
// 初始化测试用例类中由Mockito的注解标注的所有模拟对象
MockitoAnnotations.initMocks(this);
}
}
public class FreezeMoneyTaskTest extends MockitoBasedTest {
@InjectMocks
private FreezeMoneyTask freezeMoneyTask;
@Mock
private MoneyRefundDas moneyRefundDas;
@Mock
private IMoneyRefundService iMoneyRefundService;
@Test
public void before() {
TaskMessage taskMessage = new TaskMessage();
freezeMoneyTask.before(taskMessage);
}
@Test
public void execute() throws Exception {
// 初始化方法参数
TaskMessage taskMessage = new TaskMessage();
// 通过反射的方法来为私有变量赋值
int recordNum = 2;
Field recordNum1 = freezeMoneyTask.getClass().getDeclaredField("recordNum");
recordNum1.setAccessible(true);
recordNum1.set(freezeMoneyTask,recordNum);
// 有返回值的写法
List<MoneyRefundEo> select = new ArrayList<>();
MoneyRefundEo moneyRefundEo = new MoneyRefundEo();
moneyRefundEo.setCompensateNum(1);
select.add(moneyRefundEo);
Mockito.when(moneyRefundDas.selectRetryRefundList(anyInt(), anyString())).thenReturn(select);
// 无返回值的写法
Mockito.doNothing().when(moneyRefundDas).updateSelective(anyObject());
// 执行测试
freezeMoneyTask.execute(taskMessage);
}
}
其他细节可以参考这位大佬的文章:https://zhuanlan.zhihu.com/p/101026707