zoukankan      html  css  js  c++  java
  • Mockito

    1. Mockito

    单元测试开发中,我们经常会遇到测试的类有很多依赖的类、对象、资源,从而形成巨大的依赖树,mock可以模拟外部依赖,适应单元测试。
    比如我们在开发中很容易出现这种情况:
    (a)依赖(b)依赖(c)依赖(d)
    这种情况下单元测试就变得极其复杂,而且如果需要测试数据库或网络请求返回值的情况,就更加复杂了。我们总不至于去修改真实数据库,去修改真实的网络情况吧。
    但是如果我们引入Mockito情况就会变得简单许多,我们可以mock虚拟的依赖,并可以轻松的修改返回值甚至抛出异常:
    (a)依赖(mock b)

    1.1 Mockito 的简单用法

    Mockito是一个功能非常丰富的框架,下面介绍几个典型和常用的方法,详细的使用可以到官网上查询。
    我们在非Spring Boot项目中使用Mockito需要手动引入依赖,Spring Boot项目中Mocktio的使用会在下面介绍。
    <dependency>
        <groupId>org.mockito</groupId>
        <artifactId>mockito-core</artifactId>
        <scope>test</scope>
    </dependency>

    1.1.1 mock对象

    // 模拟LinkedList 的一个对象
    LinkedList mockedList = mock(LinkedList.class);
    // 此时调用get方法,会返回null,因为还没有对方法调用的返回值做模拟
    System.out.println(mockedList.get(0));

    1.1.2 方法调用的返回值

    // 模拟获取第一个元素时,返回字符串first。 给特定的方法调用返回固定值在官方说法中称为stub。
    when(mockedList.get(0)).thenReturn("first");
    // 此时打印输出first
    System.out.println(mockedList.get(0));

    1.1.3 方法调用抛出异常

    // 模拟获取第二个元素时,抛出RuntimeException
    when(mockedList.get(1)).thenThrow(new RuntimeException());
    // 此时将会抛出RuntimeException
    System.out.println(mockedList.get(1));
    如果一个方法没有返回值类型,那么可以使用此方法模拟异常抛出
    doThrow(new RuntimeException("clear exception")).when(mockedList).clear();
    mockedList.clear();

    1.1.4 调用方法时的参数匹配

    // anyInt()匹配任何int参数,这意味着参数为任意值,其返回值均是element
    when(mockedList.get(anyInt())).thenReturn("element");
    // 此时打印是element
    System.out.println(mockedList.get(999));

    1.1.5 验证方法调用次数

    // 调用add一次
    mockedList.add("once");
    // 下面两个写法验证效果一样,均验证add方法是否被调用了一次
    verify(mockedList).add("once");
    verify(mockedList, times(1)).add("once");

    1.1.6 校验行为

    校验方法调用
    // mock creation
    List mockedList = mock(List.class);
    // using mock object
    mockedList.add("one");
    mockedList.clear();
    // verification
    verify(mockedList).add("one");
    verify(mockedList).clear();
    校验方法调用顺序
    // A. Single mock whose methods must be invoked in a particular order
    List singleMock = mock(List.class);
    //using a single mock
    singleMock.add("was added first");
    singleMock.add("was added second");
    //create an inOrder verifier for a single mock
    InOrder inOrder = inOrder(singleMock);
    //following will make sure that add is first called with "was added first, then with "was added second"
    inOrder.verify(singleMock).add("was added first");
    inOrder.verify(singleMock).add("was added second");
    // B. Multiple mocks that must be used in a particular order
    List firstMock = mock(List.class);
    List secondMock = mock(List.class);
    //using mocks
    firstMock.add("was called first");
    secondMock.add("was called second");
    //create inOrder object passing any mocks that need to be verified in order
    InOrder inOrder = inOrder(firstMock, secondMock);
    //following will make sure that firstMock was called before secondMock
    inOrder.verify(firstMock).add("was called first");
    inOrder.verify(secondMock).add("was called second");
    // Oh, and A + B can be mixed together at will
    校验方法是否从未调用
    //using mocks - only mockOne is interacted
    mockOne.add("one");
    //ordinary verification
    verify(mockOne).add("one");
    //verify that method was never called on a mock
    verify(mockOne, never()).add("two");
    //verify that other mocks were not interacted
    verifyZeroInteractions(mockTwo, mockThree);

    1.2 Mockito 在 Spring Boot 中的使用

    上面我们提到了非 Spring Boot 需要手动引入 Mocktio 的依赖,但在 Spring Boot 项目中,Spring Boot Test 默认依赖 Mocktio ,所以只要依赖了 Spring Boot Test 就不再需要我们手动引入依赖。
    <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test</artifactId>
    <scope>test</scope>
    </dependency>
    一般情况下,单元测试不需要 Spring 的启动。此时我们按下面的写法:
    import static org.mockito.Mockito.*;
     
    public class MyServiceTest {
     
    /**被单元测试的类*/
    @InjectMocks
    private MyServiceImpl myServiceImpl;
     
    /**被单元测试的类中所有的依赖*/
    @Mock
    private MyMapper myMapper;
     
    /**在单元测试之前,执行Mockito的注解扫描,并注入依赖*/
    @Before
    public void setUp() { MockitoAnnotations.initMocks(this); }
     
    @Test
    public void myServiceMethod() {
    myServiceImpl.myServiceMethod();
    }
    }
    或者通过注解 RunWith 的方式:
    import static org.mockito.Mockito.*;
     
    @RunWith(SpringJUnit4ClassRunner.class)
    public class MyServiceTest {
     
    /**被单元测试的类*/
    @InjectMocks
    private MyServiceImpl myServiceImpl;
     
    /**被单元测试的类中所有的依赖*/
    @Mock
    private MyMapper myMapper;
     
    @Test
    public void myServiceMethod() {
    myServiceImpl.myServiceMethod();
    }
    }
    但有些情况下,我们可能需要 Spring 启动着。可以按下面这样写:
    import static org.mockito.Mockito.*;
     
    @SpringBootTest
    @RunWith(SpringJUnit4ClassRunner.class)
    public class MyServiceTest {
     
    /**被单元测试的类*/
    @InjectMocks
    private MyServiceImpl myServiceImpl;
     
    /**被单元测试的类中所有的依赖*/
    @Mock
    private MyMapper myMapper;
     
    @Test
    public void myServiceMethod() {
    myServiceImpl.myServiceMethod();
    }
    }
  • 相关阅读:
    IE页面后退刷新数据加载问题
    小经验: html中 js脚本运行顺序:思路整理
    jquery 之 $.end() 和 $.siblings()
    AI安防智能化发展至今还存在哪些问题?
    别 荣
    你是魔鬼 荣
    完全版权所有的DataGrid操作类及其用法 荣
    几篇关于.net1.1到.net2.0升级的文章(转载)Microsoft .NET Framework 1.1 和 2.0(测试版)兼容性 荣
    几篇关于.net1.1到.net2.0升级的文章(转载)在VS2005 正确地创建、部署和维护由1.1迁移到ASP.NET 2.0 应用程序注意事项 荣
    关于老实 荣
  • 原文地址:https://www.cnblogs.com/hansc-blog/p/10600309.html
Copyright © 2011-2022 走看看