Mockito-测试框架的运用
Mockito是什么?
1、Mockito是一个简单的流行的Mock框架。它允许你创建和配置mock对象。使用Mockito可以明显的简化对外部依赖的测试类的开发。
2、Mock测试就是在测试过程中,对某些不容易构造或者不容易获取的对象,用一个虚拟的Mock对象来创建以便测试的测试方法。
3、Mock最大的功能是帮你把单元测试的耦合分解开,如果你的代码对另一个类或者接口有依赖,它能够帮你模拟这些依赖,并帮你验证所调用的依赖的行为。
Mockito用来做什么?
Mockito可用来帮助我们完成系统的单元测试、集成测试,提高我们编码的质量和可靠性。
Mockito的使用步骤
一般使用 Mockito 需要执行下面几个步骤:
- 初始化Mockito的注解。
- 模拟并替换测试代码中外部依赖;
- 执行测试代码;
- 验证测试代码是否被正确的执行。
Mockito注解初始化
要让Mockito的注解工作起来还需要进行初始化工作。
初始化的方法为:MockitoAnnotations.initMocks(testClass)参数testClass是你所写的测试类。一般情况下在Junit4的@Before定义的方法中执行初始化工作,如下:
Java代码
@Before
public void initMocks() {
MockitoAnnotations.initMocks(this);
}
除了上述的初始化的方法外,还可以使用Mockito提供的Junit Runner:MockitoJUnitRunner这样就省略了上面的步骤。
Java代码
@RunWith(MockitoJUnit44Runner.class)
public class ExampleTest {
...
}
Mockito主要注解
1、@Spy
@Spy注解用于监视真实的对象实例,它生成的对象实例不受Spring管理。
@Spy注解生成的对象实例默认会调用真实的方法,执行方法内部的逻辑,有返回值的返回真实的返回值。
2、@SpyBean
@SpyBean注解生成的对象实例受Spring管理,相当于自动替换对应类型bean的注入,比如@Autowired等注入。
但与@Spy不同的是,它不会生成一个Bean的替代品装配到类中,而是会监听一个真正的 Bean 中某些特定的方法,并在调用这些方法时给出指定的反馈。却不会影响这个 Bean 其它的功能。
@SpyBean 包裹着真正的Bean装配到了依赖它的业务对象中,并对特定的行为作出反应。
3、@Mock
@Mock主要用于预先设定对象实例的行为逻辑,即模拟方法的返回值等等。
使用@Mock注解来定义mock对象有如下的优点:
- 方便mock对象的创建。
- 减少mock对象创建的重复代码。
- 提高测试代码可读性。
- 变量名字作为mock对象的标示,所以易于排错。
4、@MockBean
@MockBean注解生成的对象实例受Spring管理,相当于自动替换对应类型bean的注入,比如@Autowired等注入。
@MockBean包裹着模拟的Bean装配到了依赖它的业务对象中,并对特定的行为作出反应。
5、@InjectMocks注解
通过这个注解,可实现自动注入mock对象。
当前版本只支持setter的方式进行注入,Mockito首先尝试类型注入,如果有多个类型相同的mock对象,那么它会根据名称进行注入。
当注入失败的时候Mockito不会抛出任何异常,所以你可能需要手动去验证它的安全性。
Mockito注解使用示例
银行报文组装类代码
/**
* 工行-查询余额-组装指令类
*
* @author chenlw
* @since 2020/03/20
*/
@Component
public class IcbcQueryBalanceAssembler {
/**
* 组装查询余额报文
*
* @param accountInfo 账户信息
* @return 查询余额报文
*/
public Object getQueryBalanceOutput(Object accountInfo) {
System.out.println("=======组装账户余额查询报文 start=====");
System.out.println("执行组装账户余额查询报文操作1");
System.out.println("执行组装账户余额查询报文操作2");
System.out.println("执行组装账户余额查询报文操作3");
System.out.println("·····");
System.out.println("=======组装账户余额查询报文 end=====");
System.out.println();
return "账户余额查询报文";
}
}
@Spy注解使用示例
测试代码:
public class IcbcQueryBalanceAssemblerSpyTest {
@Spy
private IcbcQueryBalanceAssembler icbcQueryBalanceAssemblerSpy;
@Before
public void init() throws Exception {
// 初始化Mock类
MockitoAnnotations.initMocks(this);
}
/**
* Spy注解生成的实例对象不受Spring控制,实例对象默认会调用真实的方法,有返回值的返回真实的返回值。
*/
@Test
public void testSpy() {
System.out.println("====测试@Spy注解=====");
// 实例对象默认会调用真实的方法,有返回值的返回真实的返回值。
System.out.println(icbcQueryBalanceAssemblerSpy.getQueryBalanceOutput("test"));
System.out.println();
}
}
输出结果:
====测试@Spy注解=====
=======组装账户余额查询报文 start=====
执行组装账户余额查询报文操作1
执行组装账户余额查询报文操作2
执行组装账户余额查询报文操作3
·····
=======组装账户余额查询报文 end=====
账户余额查询报文
输出结果为对象实例的真实行为。
@SpyBean注解使用示例
示例代码:
@RunWith(SpringRunner.class)
@SpringBootTest(classes = SpringBootMockitoApplicationTest.class)
public class IcbcQueryBalanceAssemblerSpyBeanTest {
@SpyBean
private IcbcQueryBalanceAssembler icbcQueryBalanceAssemblerSpyBean;
@Before
public void init() throws Exception {
// 初始化Mock类
MockitoAnnotations.initMocks(this);
}
/**
* SpyBean注解生成的对象实例受Spring管理,相当于自动替换对应类型bean的注入,比如@Autowired等注入。
*/
@Test
public void testSpyBean() {
System.out.println("====测试@SpyBean注解=====");
// 实例对象默认会调用真实的方法,有返回值的返回真实的返回值。
System.out.println(icbcQueryBalanceAssemblerSpyBean.getQueryBalanceOutput("test"));
System.out.println();
}
@Test
public void testSpyBean1() {
System.out.println("====测试@SpyBean注解=====");
Mockito.when(icbcQueryBalanceAssemblerSpyBean.getQueryBalanceOutput(Mockito.any())).thenReturn("===当调用该方法时,返回此模拟数据===");
// 对特定的行为作出反应。
System.out.println(icbcQueryBalanceAssemblerSpyBean.getQueryBalanceOutput("test"));
System.out.println();
}
}
测试真实行为代码:
@Test
public void testSpyBean() {
System.out.println("====测试@SpyBean注解=====");
// 实例对象默认会调用真实的方法,有返回值的返回真实的返回值。
System.out.println(icbcQueryBalanceAssemblerSpyBean.getQueryBalanceOutput("test"));
System.out.println();
}
输出结果:
====测试@SpyBean注解=====
=======组装账户余额查询报文 start=====
执行组装账户余额查询报文操作1
执行组装账户余额查询报文操作2
执行组装账户余额查询报文操作3
·····
=======组装账户余额查询报文 end=====
账户余额查询报文
输出结果为对象实例的真实行为。
对特定的行为作出反应的测试代码:
@Test
public void testSpyBean1() {
System.out.println("====测试@SpyBean注解=====");
Mockito.when(icbcQueryBalanceAssemblerSpyBean.getQueryBalanceOutput(Mockito.any())).thenReturn("===当调用该方法时,返回此模拟数据===");
// 对特定的行为作出反应。
System.out.println(icbcQueryBalanceAssemblerSpyBean.getQueryBalanceOutput("test"));
System.out.println();
}
输出结果:
====测试@SpyBean注解=====
=======组装账户余额查询报文 start=====
执行组装账户余额查询报文操作1
执行组装账户余额查询报文操作2
执行组装账户余额查询报文操作3
·····
=======组装账户余额查询报文 end=====
===当调用该方法时,返回此模拟数据===
方法返回值返回的是预先设定的值,并非真实返回值。
@Mock注解使用示例
示例代码:
public class IcbcQueryBalanceAssemblerMockTest {
@Mock
private IcbcQueryBalanceAssembler icbcQueryBalanceAssemblerMock;
@Before
public void init() throws Exception {
// 初始化Mock类
MockitoAnnotations.initMocks(this);
}
/**
* Mock注解主要用于预先设定对象实例的行为逻辑,即模拟方法的返回值等等。
*/
@Test
public void testMock() {
System.out.println("=====测试@Mock注解=====");
Mockito.when(icbcQueryBalanceAssemblerMock.getQueryBalanceOutput(Mockito.any())).thenReturn("===当调用该方法时,返回此模拟数据===");
// 执行mock预先设定的返回信息,不会执行它原本真实的代码,所以没有打印该方法内部的任何信息
System.out.println(icbcQueryBalanceAssemblerMock.getQueryBalanceOutput("test"));
System.out.println();
}
}
对特定的行为作出反应的测试代码:
@Test
public void testMock() {
System.out.println("=====测试@Mock注解=====");
Mockito.when(icbcQueryBalanceAssemblerMock.getQueryBalanceOutput(Mockito.any())).thenReturn("===当调用该方法时,返回此模拟数据===");
// 执行mock预先设定的返回信息,不会执行它原本真实的代码,所以没有打印该方法内部的任何信息
System.out.println(icbcQueryBalanceAssemblerMock.getQueryBalanceOutput("test"));
System.out.println();
}
输出结果:
=====测试@Mock注解=====
===当调用该方法时,返回此模拟数据===
执行mock预先设定的返回信息,不会执行它原本真实的代码,所以没有打印该方法内部的任何信息
@MockBean注解使用示例
示例代码
@RunWith(SpringRunner.class)
@SpringBootTest(classes = SpringBootMockitoApplicationTest.class)
public class IcbcQueryBalanceAssemblerMockBeanTest {
@MockBean
private IcbcQueryBalanceAssembler icbcQueryBalanceAssemblerMockBean;
@Before
public void init() throws Exception {
// 初始化Mock类
MockitoAnnotations.initMocks(this);
}
/**
* MockBean注解生成的对象实例受Spring管理,相当于自动替换对应类型bean的注入,比如@Autowired等注入。
*/
@Test
public void testMockBean() {
System.out.println("=====测试@MockBean注解=====");
Mockito.when(icbcQueryBalanceAssemblerMockBean.getQueryBalanceOutput(Mockito.any())).thenReturn("===当调用该方法时,返回此模拟数据===");
// 执行mock预先设定的返回信息,不会执行它原本真实的代码,所以没有打印该方法内部的任何信息
System.out.println(icbcQueryBalanceAssemblerMockBean.getQueryBalanceOutput("test"));
System.out.println();
}
}
输出结果:
=====测试@MockBean注解=====
===当调用该方法时,返回此模拟数据===
执行mock预先设定的返回信息,不会执行它原本真实的代码,所以没有打印该方法内部的任何信息
源代码地址:https://github.com/chenliwu/my-spring-boot-example/tree/master/spring-boot-mockito