Mock 模拟测试简介及 Mockito 使用入门

img
img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上软件测试知识点,真正体系化!

由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新

需要这份系统化的资料的朋友,可以戳这里获取

Mock 可以交给用户

在有些情况下,某种原因你需要允许一些外部来源访问你的测试系统,像合作伙伴或者客户。这些原因导致别人也可以访问你的敏感信息,而你或许只是想允许访问部分测试环境。在这种情况下,如何向合作伙伴或者客户提供一个测试系统来开发或者做测试呢?最简单的就是提供一个mock,无论是来自于你的网络或者客户的网络。soapUI mock非常容易配置,他可以运行在soapUI或者作为一个war包发布到你的java服务器里面。


隔离系统

有时,你希望在没有系统其他部分的影响下测试系统单独的一部分。由于其他系统部分会给测试数据造成干扰,影响根据数据收集得到的测试结论。使用mock你可以移除掉除了需要测试部分的系统依赖的模拟。当隔离这些mocks后,mocks就变得非常简单可靠,快速可预见。这为你提供了一个移除了随机行为,有重复模式并且可以监控特殊系统的测试环境。


Mockito

介绍

Mockito 是一个简单的流行的 Mock 框架。它能够帮我们创建 Mock 对象,保持单元测试的独立性。

使用它只需要在 Maven 中添加依赖即可。

<!-- https://mvnrepository.com/artifact/org.mockito/mockito-all -->
    <dependency>
        <groupId>org.mockito</groupId>
        <artifactId>mockito-all</artifactId>
        <version>2.0.2-beta</version>
    </dependency>

创建 Mock 对象

通过方法创建
class CreateMock {
	@Before
	public void setup() {
		mockUserDao = mock(UserDao.class);  
        userService = new UserServiceImpl();  
        userService.setUserDao(mockUserDao);  
	}
}

通过注解创建
class CreateMock {
	@Mock
	UserDao mockUserDao;
	
	@InjectMocks  
    private UserServiceImpl userService;  

	@Before  
    public void setUp() {  
	    //初始化对象的注解 
        MockitoAnnotations.initMocks(this);  
    }  
}


一个简单的例子:

package Mockito;

import org.junit.Assert;
import org.junit.Test;
import java.util.List;

import static org.mockito.Mockito.*;

public class MyTest {
    @Test
    public void myTest() {
	    /\* 创建 Mock 对象 \*/
        List list = mock(List.class);
		/\* 设置预期,当调用 get(0) 方法时返回 "111" \*/
        when(list.get(0)).thenReturn("111");

        Assert.assertEquals("asd", 1, 1);
        /\* 设置后返回期望的结果 \*/
        System.out.println(list.get(0));
        /\* 没有设置则返回 null \*/
        System.out.println(list.get(1));

        /\* 对 Mock 对象设置无效 \*/
        list.add("12");
        list.add("123");
        /\* 返回之前设置的结果 \*/
        System.out.println(list.get(0));
        /\* 返回 null \*/
        System.out.println(list.get(1));
        /\* size 大小为 0 \*/
        System.out.println(list.size());

        /\* 验证操作,验证 get(0) 调用了 2 次 \*/
        verify(list, times(2)).get(0);

		/\* 验证返回结果 \*/
        String ret = (String)list.get(0);
        Assert.assertEquals(ret, "111");
    }
}

从上面代码能看出一般使用的步骤:

设置方法预期返回

通过 when(list.get(0)).thenReturn(“111”); 来设置当调用 list.get(0) 时返回 “111”,该方法就是 Stub,替换我们实际的操作。

验证方法调用

该方法验证 get(0) 方法调用的次数 verify(list, times(2)).get(0);,还可以设置是否调用过,调用时间等等。

验证返回值

Assert.assertEquals(ret, “111”); 方法验证 Mock 对象方法调用后的返回值是否达到预期。


Mockito 使用

设置 Mock 对象期望和返回值

/\* 表示第一次调用 someMethod() 返回 value1 第二次调用返回 value2 \*/
when(mock.someMethod()).thenReturn(value1).thenReturn(value2);  
when(mock.someMethod()).thenReturn(value1, value2);  
/\* 也可以设置两次 \*/
when(mock.someMethod()).thenReturn(value1);
when(mock.someMethod()).thenReturn(value2);

另外一种写法 doReturn()

/\* 表示第一次调用 someMethod() 返回 value1 第二次调用返回 value2 \*/
doReturn(value1).doReturn(value2).when(mock).someMethod();  
/\* 若返回 void,则设置为 doNothing() \*/
doNothing().when(mock).someMethod();

对方法设定返回异常

/\* 当调用 someMethod() 方法时会抛出异常 \*/
when(mock.someMethod()).thenThrow(new RuntimeException());
/\* 对 void 方法设定 \*/  
doThrow(new RuntimeException()).when(mock).someMethod();  

参数匹配器

我们不一定要固定 Stub 调用时的参数,如 get(0)。可以通过参数匹配器来调用。

when(list.get(anyInt())).thenReturn("hello");


Mock 对象的行为验证

package Mockito;

import org.mockito.ArgumentCaptor;
import org.mockito.InOrder;
import org.testng.annotations.Test;

import java.util.List;
import static org.mockito.Mockito.*;

/\*\*
 \* Created by andy.wwh on 2016/7/18.
 \*/
public class Behavior {
    @Test
    public void behaviorCheck() {
        List mock1 = mock(List.class);
        List mock2 = mock(List.class);

        /\* 设置预期 \*/
        when(mock1.get(0)).thenReturn("hello world");
        when(mock1.get(1)).thenReturn("hello world");
        when(mock2.get(0)).thenReturn("hello world");
        mock1.get(0);

        /\* 验证方法调用一次 \*/
        verify(mock1).get(0);
        mock1.get(0);
        /\* 验证方法调用两次 \*/
        verify(mock1, times(2)).get(0);
        /\* 验证方法从未被调用过 \*/
        verify(mock2, never()).get(0);
        /\* 验证方法 100 毫秒内调用两次 \*/
        verify(mock1, timeout(100).times(2)).get(anyInt());

        /\* 设置方法调用顺序 \*/
        InOrder inOrder = inOrder(mock1, mock2);
        inOrder.verify(mock1, times(2)).get(0);
        inOrder.verify(mock2, never()).get(1);

        /\* 查询是否存在被调用,但未被 verify 验证的方法 \*/
        verifyNoMoreInteractions(mock1, mock2);
        /\* 验证 Mock 对象是否没有交发生 \*/
        verifyZeroInteractions(mock1, mock2);

        /\* 参数捕获器 \*/
        ArgumentCaptor<Integer> argumentCaptor = ArgumentCaptor.forClass(Integer.class);
        verify(mock1, times(2)).get(argumentCaptor.capture());
        System.out.println("argument:" + argumentCaptor.getValue());
    }
}

验证调用次数

verify(mock1, timeout(100).times(2)).get(anyInt());

除了代码中的方法,Mockito 还提供了

  • never() 没有被调用,相当于times(0)
  • atLeast(N) 至少被调用N次
  • atLeastOnce() 相当于atLeast(1)
  • atMost(N) 最多被调用N次
超时验证

通过 timeout 我们可以进行验证程序执行时间是否符合规则。

方法调用顺序

Inorder 可以验证方法调用的顺序

verifyNoMoreInteractions 和 verifyZeroInteractions

verifyNoMoreInteractions:查询是否存在被调用,但未被 verify 验证的方法

verifyZeroInteractions:verifyZeroInteractions

ArgumentCaptor 参数捕获器

可在验证时对方法的参数进行捕获,最后验证捕获的参数值。如果方法有多个参数都要捕获验证,那就需要创建多个ArgumentCaptor对象处理。


Spy 对象验证

Mock 操作的全是虚拟对象。即使我们设置了 when(list.get(0)).thenReturn(1),我们调用如 size() 方法返回的还是 0。Mockito 还给我们提供了一种对真实对象操作的方法——Spy

做一个简单的比较:

package Mockito;

import org.testng.annotations.Test;

import java.util.List;

import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

/\*\*
 \* Created by andy.wwh on 2016/7/18.
 \*/
public class MockObject {
    @Test
    public void MockTest() {
        List list = mock(List.class);

        when(list.get(0)).thenReturn("hello world");

        System.out.println(list.get(0));

        System.out.println(list.size());
    }
}

package Mockito;

import org.testng.annotations.Test;

import java.util.LinkedList;
import java.util.List;

import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.when;

/\*\*
 \* Created by andy.wwh on 2016/7/18.
 \*/
public class MockObject {
    @Test
    public void MockTest() {
	    /\* 创建真实对象 \*/
        List list = new LinkedList();
        List spy = spy(list);

        spy.add("hello");

        when(spy.get(0)).thenReturn("hello world");

        System.out.println(spy.get(0));
    }
}

看个官网的例子:

@Test  
public void spyTest() {  
    List list = new LinkedList();  
    List spy = spy(list);  
    // optionally, you can stub out some methods: 
    when(spy.size()).thenReturn(100);  
    // using the spy calls real methods 
    spy.add("one");  
    spy.add("two");  
    // prints "one" - the first element of a list 
    System.out.println(spy.get(0));  
    // size() method was stubbed - 100 is printed 
    System.out.println(spy.size());  
    // optionally, you can verify 
    verify(spy).add("one");  
    verify(spy).add("two");  
}  


参考:

img
img

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化的资料的朋友,可以戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

e());
// optionally, you can verify
verify(spy).add(“one”);
verify(spy).add(“two”);
}




---


参考:


[外链图片转存中...(img-BEPJyFPg-1715808466798)]
[外链图片转存中...(img-8oQ7npiu-1715808466799)]

**网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。**

**[需要这份系统化的资料的朋友,可以戳这里获取](https://bbs.csdn.net/topics/618631832)**

**一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!**

  • 17
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值