• 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/

  • 相关阅读:
    前端小tite(随笔)
    算法两数之和 python版
    常用标签
    pip install 遇到的问题
    不常用的模块
    约束和约束关系
    Django初识
    前端—Bootstrap
    前端—jQuery
    前端—BOM和DOM
  • 原文地址:https://www.cnblogs.com/heyang78/p/12462415.html
Copyright © 2020-2023  润新知