Mockito使用说明

一、 Mockito简介

1. Mockito是什么

1、官方解释: Mockito is a mocking framework that tastes really good. It lets you write beautiful tests with a clean & simple API. Mockito doesn’t give you hangover because the tests are very readable and they produce clean verification errors.

2、Mockito是简单轻量级的Mocking(模拟测试)框架。使用简单,测试代码可读性高,能够使单元测试尽可能独立。

2. Mockito较于Junit的优势

1、JUnit可以轻松完成关联依赖关系少或者比较简单的单元测试,但是对于关联依赖关系较多的类或者对运行环境有要求的类的单元测试,模拟环境或者配置环境时会非常耗时,实施单元测试较为困难。例如需要需要测试一个controller方法,需要从controller->service->dao层,这种方法无疑是正确的,但是有一个很明显的问题,速度问题。测试controller层时会访问下面两层,如果我们之前已经测试过service,dao层是正确的,现在相当于做了两次重复的动作。

2、Mockito可以模拟对象的行为,隔离开我们不关心的其他对象,使测试变得简单。图解及代码示例:
在这里插入图片描述

1.	public class UserService(){ 
2.	         //...
3.	    public void saveUser(User user){  
4.	        {  
5.	            //...  
6.	        }  
7.	        // 访问数据库方法  
8.	        userDao.insertUser(new User());  
9.	        {  
10.	            //...  
11.	        }  
12.	    }  
13.	}  
14.	public class UserDao(){  
15.	      
16.	    public void insertUser(){  
17.	        // 数据库此时不能访问
18.	        throw new RuntimeException("databaser cant connect");  
19.	    }  
20.	      
21.	}  

3. Mockito执行步骤

  1. 模拟并替换测试代码中外部依赖。

  2. 执行测试代码。

  3. 执行测试代码是否被正确执行。

4. Mockito检测方式

1)状态检测(state verification),方法运行过之后,检测方法的运行状态(或者说返回值状态),判断方法运行是否成功。

1.	assertNotNull(user);                      // 验证返回值时候为空  
2.	assertEquals(user.getUserName(), "tom");  // 验证返回值时候等于预期值  
3.	assertTrue(biilean);                      // 验证返回值是否为true

2)行为检测(behavior verification),方法运行之后,检测方法的执行行为(或者说执行顺序),判断方法是否执行成功。

1.	verify(mockUserService).findUserByUserName("tom"); // 验证交互行为  
2.	verify(mockUserService, atLeastOnce()).findUserByUserName("tom");// 方法至少调用一次  
3.	verify(mockUserService, atLeast(1)).findUserByUserName("tom");       
4.	verify(mockUserService, atMost(1)).findUserByUserName("tom"); // 方法至多调用一次  

5. Mockito资源

官网:

http://mockito.org

项目源码:

https://github.com/mockito/mockito

API文档:

https://static.javadoc.io/org.mockito/mockito-core/3.0.0/org/mockito/Mockito.html

教程:

https://www.cnblogs.com/Ming8006/p/6297333.html

https://www.jianshu.com/p/f6e3ab9719b9

二、 Mockito的使用

1. 依赖添加

Mockito依赖,需配合Junit使用

1)	<dependency>  
2)	    <groupId>org.mockito</groupId>  
3)	    <artifactId>mockito-core</artifactId>  
4)	    <version>1.10.19</version>  
5)	    <scope>test</scope>  
6)	</dependency>  
7)	  
8)	<dependency>  
9)	    <groupId>org.mockito</groupId>  
10)	    <artifactId>mockito-all</artifactId>  
11)	    <version>1.10.19</version>  
12)	    <scope>test</scope>  
13)	</dependency>  
 

2. Mockito API使用方式

1) 静态引用

如果在代码中静态引用了org.mockito.Mockito.*;,那你你就可以直接调用静态方法和静态变量而不用创建对象,

1.	import static org.mockito.Mockito.verify;  
2.	import static org.mockito.Matchers.*;  
3.	import static org.mockito.Mockito.times;  
4.	import static org.mockito.Mockito.verify;  
5.	import static org.mockito.Mockito.when;  

2) 使用Mockito创建mock对象

(一) 除了上面所说的使用 mock() 静态方法外,Mockito 还支持通过 @Mock 注解的方式来创建 mock 对象。

(二) @Mock 是对于测试类的依赖类的注解,被 @Mock 标记后相当于创建了一个Mock对象,不会进入方法体。

(三) @InjectMocks 是对待测试类的注解,创建一个实例,其余使用@Mock或@Spy注解的Mock将会被注解到该实例中,所有方法都会进入方法体。

(四) Mockito在遇到使用注解的字段的时候,会调用MockitoAnnotations.initMocks(this) 来初始化该 mock 对象。另外也可以通过使用@RunWith(MockitoJUnitRunner.class)来达到相同的效果。

3. Mockito测试方法

1) Service层测试

1.	@RunWith(MockitoJUnitRunner.class)  
2.	public class ServiceMockitoTest {  
3.	  
4.	    // Dao对象  
5.	    @Mock  
6.	    UserDao userDao;  
7.	
8.	    // 被测试Service对象  
9.	    @InjectMocks  
10.	    UserService userService;  
11.	  
12.	    @Test  
13.	    public void serviceMockito(){  
14.	  
15.	        User user = new User();  
16.	        // 当UserDao的insertUser方法被UserService的regist方法调用时返回1
17.	        when(userDao.insertUser(any(User.class))).thenReturn(1);  
18.	        // 验证方法调用  
19.	        assertTrue(userService.regist(user));
20.	    }  
21.	}  

2) Controller层测试

:
测试时URL参数应当与Mock时参数保持一致,否则mock不成功。
1.	@ContextConfiguration(classes = MockServletContext.class)  
2.	public class ControllerMockitoTest {  
3.	  
4.	    private MockMvc mockMvc;  
5.	  
6.	    @Mock  
7.	    UserService userService;  
8.	  
9.	    @InjectMocks  
10.	    UserController userController;  
11.	  
12.	    @Before  
13.	    public void setUp() throws Exception {  
14.	        MockitoAnnotations.initMocks(this);  
15.	        this.mockMvc = MockMvcBuilders.standaloneSetup(userController).build();  
16.	    }  
17.	  
18.	  
19.	    @Test  
20.	    public void mockitoTest() throws Exception {  
21.	        //mock void方法
22.	        Mockito.doNothing().when(userService).deleteUser(Mockito.anyInt()); 
23.	        //构建请求,与接口路径一致  
24.	        RequestBuilder request = MockMvcRequestBuilders.post("/user/1");  
25.	        //断言请求是否成功  
26.	        mockMvc.perform(request).andExpect(MockMvcResultMatchers.status().isOk());  
27.	    }  
28.	}  

3) 异常测试

1.	@RunWith(MockitoJUnitRunner.class)  
2.	public class ExceptionMockitoTest {  
3.	 
4.	    @Mock  
5.	    UserDao userDao;  
6.	  
7.	    @InjectMocks  
8.	    UserService userService;  
9.	  
10.	    @Test  
11.	    public void MockitoTest(){  
12.	        User user = new User();  
13.	        // 调用userDao的updateUser方法时抛出RuntimeException  
14.	        doThrow(new RuntimeException("operation notimplemented")).when(userDao).updateUser(any(User.class));  
15.	        // 异常后断言  
16.	        assertTrue(userService.update(user));  
17.	    }  
18.	}  

4) 静态方法测试

注:

  1. Mockito可以对普通方法进行Mock,如public等,如要对private/static/final进行Mock,需要配合PowerMock。

  2. Mockito与PowerMock存在版本兼容问题,对应版本。https://blog.csdn.net/fengliushaonian1993/article/details/78241932

  3. 依赖

    1.	<dependency>  
    2.	    <groupId>org.powermock</groupId>  
    3.	    <artifactId>powermock-api-mockito</artifactId>  
    4.	    <version>1.6.3</version>  
    5.	    <scope>test</scope>  
    6.	</dependency>  
    7.	<dependency>  
    8.	    <groupId>org.powermock</groupId>  
    9.	    <artifactId>powermock-module-junit4</artifactId>  
    10.	    <version>1.6.3</version>  
    11.	    <scope>test</scope>  
    12.	</dependency>  
    
    
    @RunWith(PowerMockRunner.class)
    @PrepareForTest(UserDao.class)
    public class UserServiceStaticTest {
    
        @Test
        public void queryUserCount() {
            // powerMock的静态方法支持
            mockStatic(UserDao.class);
            // 当调用UserDao的静态方法getCount时,返回10
            when(UserDao.getCount()).thenReturn(10);
            // 调用方法userService.queryUserCount()的方法
            UserService userService = new UserService();
            int count = userService.queryUserCount();
            // 断言结果是否为预期值
            assertEquals(10 , count);
        }
    
        @Test
        public void saveUser() {
            User user = new User();
            // powerMock的静态方法支持
            mockStatic(UserDao.class);
            // void返回类型doNothing
            PowerMockito.doNothing().when(UserDao.class);
            // 调用方法userService.saveUser(user)的方法
            UserService userService = new UserService();
            userService.saveUser(user);
            // 验证是否执行成功
            PowerMockito.verifyStatic();
        }
    }
    

5) 私有方法测试

注:

public方法中常会调用私有方法,如果只想测试public方法,不关注private的逻辑,就需要对private方法进行Mock。

@RunWith(PowerMockRunner.class)
@PrepareForTest(UserService.class)
public class UserServicePrivateTest {

    @Test
    public void log() {
        /*// mock对象不进入方法体
        UserService userService1 = PowerMockito.mock(UserService.class);
        userService1.log("e");

        // spy对象进入方法体
        // 满足断言条件使用mock, 不满足使用spy
        UserService userService2 = PowerMockito.spy(new UserService());
        userService2.log("e");*/


        UserService userService3 = PowerMockito.spy(new UserService());
        String arg = "log";
        doNothing().when(userService3).log(arg);
        // 不符合断言, 使用soy会进入方法体
        // userService3.log("test");
        // 符合断言,使用mock不会进入方法体
        userService3.log("arg");
    }

    @Test
    public void exists() throws Exception {
        // spy userService对象
        UserService userService = PowerMockito.spy(new UserService());
        // 当实行userService的checkExists并且参数为qyh时,返回true
        PowerMockito.doReturn(true).when(userService, "checkExists", "qyh");
        // 断言
        assertTrue(userService.exists("qyh"));
    }
}

6) Final类测试

@RunWith(PowerMockRunner.class)
@PrepareForTest(UserDao.class)
public class UserServiceFinalTest {

    @Mock
    private UserDao userDao;

    @Test
    @Ignore
    public void queryUserCountWithMockito() {
        // 初始化UserDao的mock对象
        MockitoAnnotations.initMocks(this);
        UserService userService = new UserService(userDao);
        // 调用UserDao的final方法getCount时,返回10
        when(userService.queryUserCount()).thenReturn(10);
        int count = userService.queryUserCount();
        // 断言结果是否为预期
        assertEquals(10, count);
    }

    @Test
    public void queryUserCountWithPowerMock() {
        // 调用UserDao的final方法getCount时,返回10
        PowerMockito.when(userDao.getCount()).thenReturn(10);
        UserService userService = new UserService(userDao);
        int count = userService.queryUserCount();
        // 断言结果是否为预期值
        assertEquals(10 , count);
    }

}

9) Final方法测试

t);
}

@Test
public void queryUserCountWithPowerMock() {
    // 调用UserDao的final方法getCount时,返回10
    PowerMockito.when(userDao.getCount()).thenReturn(10);
    UserService userService = new UserService(userDao);
    int count = userService.queryUserCount();
    // 断言结果是否为预期值
    assertEquals(10 , count);
}

}




### 9)    Final方法测试

测试方式与Final类测试方法一致,将Final类改为Final方法,其他代码不变。


代码下载地址 : https://download.csdn.net/download/qq_37813031/12198273
  • 3
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值