mockito使用
为什么使用mockito
设想一个刚开始学习编程的学生如何处理测试?
public static void main(String[] args) {
List<String> strings = Lists.newArrayList("string1", "string2");
if(!"STRING1".equals(strings)) {
throw new SomeException();
}
}
一般情况下需要这三步走:
- 新建一个执行入口main
- 编写一些测试数据
- 执行逻辑,然后看一下逻辑是否与自己设想的一致
这个流程正确吗?没问题的,这个流程是完整的,且可行的; 但是,比较麻烦,麻烦的地方在于总是需要新建一个主类入口,总是需要肉眼看下是否符合逻辑;(好像总是需要编写测试数据不好避过?)
那么,如何优雅的处理这个问题呢?
- junit: 控制测试流程,处理测试事务
- mockito: 管理方法行为,控制方法输入输出,测试最小粒度的逻辑正确
- Assertion, Verify: 如何自动的测试一个逻辑过程的正确性 所以,测试框架主要解决的是这三个问题,下面的三个主题,主要是为了解释这三个问题。
什么是Junit,如何使用Junit
简单理解,Junit是一个能够框架性的解决单元测试的框架。意味着,你可以使用Junit来无牵连的解决单独一个子模块,一个方法的正确性。 Junit集成了很多的流程控制,数据、结论的验证方面的处理;另外,Junit更像是一个框架,可以通过Junit来赋予三方开发者对你的框架的测试能力。例如,Spring通过适配Junit,允许Spring的开发者进行Spring的测试
由于对Junit的讲解文章非常多,本文不多做Junit的使用讲解。
实例代码:
public class TestSomething {
// 添加Test表名一个最小的测试单元
@Test
public void test() {
// 调用一个服务获取到结果
int returnCode = someService.getReturnCode();
// 判断是否符合预期
assertEqual(returnCode, 0);
}
}
什么是Mockito,如何使用Mockito
理解一个问题:如果我的测试是为了测试一个最小的逻辑单元,但是因为我的逻辑单元需要用到其他的逻辑提供方(比如说一个service),那么如何能够做到不连带测试这个逻辑提供方呢?
Mockito能够解决这个问题。Mockito通过反射的机制,约束测试对象的内部行为,最小化的实现一个类的方法的逻辑。在此基础上,测试一个方法的行为;这种说法比较抽象,我们看下面的代码:
我们需要实现这样一个逻辑/方法: 这个方法被调用的时候,会从一个天气的接口中获取当天的气温,获取到气温后进行判断给出当天的警报状态
- 假设我们要测试的service如下:
public class WeatherWarningServiceImpl implements WeatherWarningService {
private static final String NORMAL = "NORMAL";
private static final String COLD = "COLD";
private static final String HOT = "HOT";
private static final int HOT_LIMIT = 30;
private static final int COLD_LIMIT = 0;
private TemperaturService tempService;
public String getWarningMsg() {
int temperature = tempService.getTemp();
if(temperature > HOT_LIMIT) {
return HOT;
}
if(temperatur < COLD_LIMIT) {
return COLD;
}
return NORMAL;
}
}
我们分析下上面这个方法:
这个方法已经是一个最小的逻辑体,但是实现的过程中使用到了一个 tempService
, 传统的测试办法中,需要使这个服务在测试中可用,这样会有很多的问题
- 大部分时候无法是这个服务可用
- 如果非得是这个服务可用的话,破坏了最小原则,单一职能原则
- 使用Spring的测试框架话,测试耗时会非常的长
如果我们只是为了测试 getWarningMsg
的逻辑是否正确,那么只要能够约束、控制tempServvice#getTemp
的行为就非常的nice:Mockito就能够起到这样的作用。继续写
@Runwith(MockitoRunner.class)
public class TestWithMockito {
/**
* 被测试的服务的对象
*/
@InjectMock
private WeatherWarningServiceImpl weatherWarningService;
// 测试对象需要的property,需要时可以实例化的类,不可以使用interface,和abstract类
@Mock
private TemperatureServiceImpl tempService;
@Test
public void test() {
// 约束 tempService的行为, 使该方法始终返回35
when(tempService.getTemp()).thenReturn(35);
String warningMsg = weatherWarningService.getWarningMsg();
assertEqual(HOT, warningMsg);
}
}