zoukankan      html  css  js  c++  java
  • Mockito在JUnit测试中的使用

    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

    反射资料2:https://www.sczyh30.com/posts/Java/java-reflection-1/

  • 相关阅读:
    codeforces C. Fixing Typos 解题报告
    codeforces B. The Fibonacci Segment 解题报告
    codeforces B. Color the Fence 解题报告
    codeforces B. Petya and Staircases 解题报告
    codeforces A. Sereja and Bottles 解题报告
    codeforces B. Levko and Permutation 解题报告
    codeforces B.Fence 解题报告
    tmp
    API 设计 POSIX File API
    分布式跟踪的一个流行标准是OpenTracing API,该标准的一个流行实现是Jaeger项目。
  • 原文地址:https://www.cnblogs.com/heyang78/p/12462415.html
Copyright © 2011-2022 走看看