Mockito是一种用于替代在测试中难以实现的成员,从而让testcase能顺利覆盖到目标代码的手段。下面例子将展示Mockito的使用。
完整代码下载:https://files.cnblogs.com/files/xiandedanteng/mockitoTest20200311.zip
首先有这么一个需要测试的类:
package mockito; public class EmpService { private EmpDao dao; public EmpService() { dao=new EmpDao(); } public boolean isWeakPswd(long empId) { // roadlock which hinder running bacause of no environment Emp emp=dao.getById(empId); // Real code need to be tested,but unreachable because emp is null if(emp.getPswd().equals("111111")) { return true; }else if(emp.getPswd().equals("123456")) { return true; }else if(emp.getName().equals(emp.getPswd())) { return true; }else { return false; } } }
其中isWeakPswd是需要测试的方法,但问题是dao不能在测试环境中就绪,因此跑不到下面的if语句。
package mockito; public class EmpDao { public Emp getById(long id) { // Access auth/redis/db to get a real emp,but it is difficult to set up environment in test,so return null return null; } }
EmpDao的getById方法不能就绪的原因是需要搭建完整的认证/redis/db环境,总之搞不成就是了。大家在测试某些类也会发生内部的mapper,dao不能就绪的情况,这和本例情况类似。
然后下面的测试方法就走不下去了,因为一跑isWeakPswd方法就会抛出空指针异常;
@Test public void normalTestWeakPswd() { EmpService service=new EmpService(); // NullPointerException will be thrown out and case will fail boolean actual=service.isWeakPswd(10001); Assert.assertSame(true, actual); }
然后怎么办呢?任凭Coverrage在低位徘徊?当然不是,这个时候就该请Mock出场了。
Mock本身就是个空壳,作用是替代无法就绪的对象,达到测试其后代码的目的。下面就制作了mockDao用来替代EmpService里的empDao
@Test public void testWeakPswd_ByMock_01() throws Exception { EmpDao mockDao = Mockito.mock(EmpDao.class); // 创建 Emp emp=new Emp(10001,"Andy","111111"); // 返回值 Mockito.when(mockDao.getById(10001)).thenReturn(emp);// 设置调用getById时返回固定值 // Use reflection replace dao with mockDao,利用反射用mock对象取代原有的empDao EmpService service=new EmpService(); Field daoField = service.getClass().getDeclaredField("dao"); daoField.setAccessible(true); daoField.set(service, mockDao); Assert.assertEquals(true, service.isWeakPswd(10001));// 这样,isWeakPswd方法就不会抛出空指针异常了 }
这样,Mock对象就当好了替补队员的角色,使得isWeakPswd的代码可以达到了。
Mockito的使用就这样简单,无非是创建,设定要模拟的函数的返回值(或异常),然后用反射方法进行顶替三部曲,下面是测试类的全部代码:
package mockitoTest; import java.lang.reflect.Field; import org.junit.Assert; import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; import org.mockito.Mockito; import mockito.Emp; import mockito.EmpDao; import mockito.EmpService; public class EmpServiceTest { @Rule public ExpectedException exception = ExpectedException.none(); // No Exception thrown Allowed private EmpDao memberMockDao; @Before public void init() throws Exception { memberMockDao = Mockito.mock(EmpDao.class); Emp emp=new Emp(10002,"Bill","123456"); Mockito.when(memberMockDao.getById(10002)).thenReturn(emp); } @Test public void normalTestWeakPswd() { EmpService service=new EmpService(); // NullPointerException will be thrown out and case will fail boolean actual=service.isWeakPswd(10001); Assert.assertSame(true, actual); } @Test public void testWeakPswd_ByMock_01() throws Exception { EmpDao mockDao = Mockito.mock(EmpDao.class); Emp emp=new Emp(10001,"Andy","111111"); Mockito.when(mockDao.getById(10001)).thenReturn(emp); // Use reflection replace dao with mockDao EmpService service=new EmpService(); Field daoField = service.getClass().getDeclaredField("dao"); daoField.setAccessible(true); daoField.set(service, mockDao); Assert.assertEquals(true, service.isWeakPswd(10001)); } @Test public void testWeakPswd_ByMock_02() throws Exception { // Use reflection replace dao with mockDao EmpService service=new EmpService(); Field daoField = service.getClass().getDeclaredField("dao"); daoField.setAccessible(true); daoField.set(service, memberMockDao); Assert.assertEquals(true, service.isWeakPswd(10002)); } @Test public void testWeakPswd_ByMock_03() throws Exception { EmpDao mockDao = Mockito.mock(EmpDao.class); Emp emp=new Emp(10003,"Cindy","Cindy"); Mockito.when(mockDao.getById(10003)).thenReturn(emp); // Use reflection replace dao with mockDao EmpService service=new EmpService(); Field daoField = service.getClass().getDeclaredField("dao"); daoField.setAccessible(true); daoField.set(service, mockDao); Assert.assertEquals(true, service.isWeakPswd(10003)); } }
要测试的EmpService类:
package mockito; public class EmpService { private EmpDao dao; public EmpService() { dao=new EmpDao(); } public boolean isWeakPswd(long empId) { // roadlock which hinder running bacause of no environment Emp emp=dao.getById(empId); // Real code need to be test,but unreachable because emp is null if(emp.getPswd().equals("111111")) { return true; }else if(emp.getPswd().equals("123456")) { return true; }else if(emp.getName().equals(emp.getPswd())) { return true; }else { return false; } } }
因伤不能上阵的EmpDao类:
package mockito; public class EmpDao { public Emp getById(long id) { // Access auth/redis/db to get a real emp,but it is difficult to set up environment in test,so return null return null; } }
实体类Emp:
package mockito; public class Emp { private long id; private String name; private String pswd; public Emp() { } public Emp(long id,String name,String pswd) { this.id=id; this.name=name; this.pswd=pswd; } public long getId() { return id; } public void setId(long id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getPswd() { return pswd; } public void setPswd(String pswd) { this.pswd = pswd; } }
要使用Mockito,可以在pom.xml里进行如以下红字部分设置:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com</groupId>
<artifactId>logbackCfg</artifactId>
<version>0.0.1-SNAPSHOT</version>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.1.11</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-core</artifactId>
<version>1.1.11</version>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>3.1.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>
--2020年3月11日--
参考资料:http://www.voidcn.com/article/p-vekqzrow-btm.html
Mock与反射关系不小,这里是反射资料:https://blog.csdn.net/a745233700/article/details/82893076