基本介绍

什么是 Mock 测试

Mock 测试就是在测试过程中,对于某些不容易构造(如 HttpServletRequest 必须在Servlet 容器中才能构造出来)或者不容易获取比较复杂的对象(如 JDBC 中的ResultSet 对象),用一个虚拟的对象(Mock 对象)来创建以便测试的测试方法。

Mock 最大的功能是帮你把单元测试的耦合分解开,如果你的代码对另一个类或者接口有依赖,它能够帮你模拟这些依赖,并帮你验证所调用的依赖的行为。

比如一段代码有这样的依赖:

testablemock mock 第三方包里面的方法 mock测试怎么使用_java


当我们需要测试A类的时候,如果没有 Mock,则我们需要把整个依赖树都构建出来,而使用 Mock 的话就可以将结构分解开,像下面这样:

testablemock mock 第三方包里面的方法 mock测试怎么使用_System_02

在哪里使用Mock对象?

  • 真实对象很难被创建的
  • 真实对象的某些行为很难被触发
  • 真实对象实际上还不存在的(正在开发中)等等

一、添加依赖

<!--mockito框架-->
        <dependency>
            <groupId>org.mockito</groupId>
            <artifactId>mockito-core</artifactId>
            <version>3.5.15</version>
            <scope>test</scope>
        </dependency>

如果在导包时报错,删掉上面的scope作用域标签

1.验证行为

@Test
    public void test1() {

        // 可以模拟一个接口
        List mockedList = mock(List.class);

        // 然后可以直接使用接口的方法
        mockedList.add("one");
        mockedList.clear();

        //verification  验证是否发生某种行为,发生了,啥都不做,未发生,报错
        // 下面这句会报错,因为 add的是one而不是two
        // verify(mockedList).add("two");

        verify(mockedList).clear();
    }

2.模拟一个实体类

@Test
    public void test2() {

        // mock一个具体的类,产生mock后的对象
        LinkedList mockedList = mock(LinkedList.class);


        when(mockedList.get(0)).thenReturn("first");
        when(mockedList.get(1)).thenThrow(new RuntimeException("我自己抛出的异常"));

        // following prints "first"
        System.out.println(mockedList.get(0));

        // following throws runtime exception
        // System.out.println(mockedList.get(1));

        // null 因为没有存过999
        System.out.println(mockedList.get(999));

        mockedList.add("11111");

        // 猜想:因为不是真实对象,所以size()始终为 0
        System.out.println(mockedList.size());

        // 验证调用了get(0)
        verify(mockedList).get(0);

    }

3.参数匹配器

@Test
    public void test3() {

        // mock一个具体的类,产生mock后的对象
        LinkedList mockedList = mock(LinkedList.class);

        //stubbing using built-in anyInt() argument matcher
        when(mockedList.get(anyInt())).thenReturn("element");

        when(mockedList.contains(argThat(new Matches("ssss")))).thenReturn(true);
        // 可以使用正则表达式,没搞清楚怎么用的,下面返回true
        System.out.println(mockedList.contains("ssss"));


        //following prints "element"
        System.out.println(mockedList.get(999));

        //you can also verify using an argument matcher
        verify(mockedList).get(anyInt());
    }

4.验证方法调用的次数

@Test
    public void test4() {

        // mock一个具体的类,产生mock后的对象
        LinkedList mockedList = mock(LinkedList.class);

        mockedList.add("once");
        mockedList.add("twice");
        mockedList.add("twice");

        mockedList.add("three times");
        mockedList.add("three times");
        mockedList.add("three times");

        //following two verifications work exactly the same - times(1) is used by default
        verify(mockedList).add("once");
        verify(mockedList, times(1)).add("once");

        //exact number of invocations verification
        verify(mockedList, times(2)).add("twice");
        verify(mockedList, times(3)).add("three times");

        //verification using never(). never() is an alias to times(0)
        verify(mockedList, never()).add("never happened");

        // 验证最少、最多调用的次数
        verify(mockedList, atLeastOnce()).add("three times");


        // verify(mockedList, atLeast(2)).add("five times");

        verify(mockedList, atMost(5)).add("three times");
    }

5.模拟方法抛出异常

@Test
    public void test5() {

        // mock一个具体的类,产生mock后的对象
        LinkedList mockedList = mock(LinkedList.class);

        doThrow(new RuntimeException("我就抛出异常了")).when(mockedList).clear();

        //调用的时候就会抛出异常
        mockedList.clear();
    }

6.验证方法调用的顺序

@Test
    public void test6() {

        // 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);

        // 验证方法调用的顺序, 如果下面列出的顺序和调用的顺序一样,则通过,否则抛出异常
        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 inOrder2 = inOrder(firstMock, secondMock);

        //following will make sure that firstMock was called before secondMock
        inOrder2.verify(firstMock).add("was called first");
        inOrder2.verify(secondMock).add("was called second");
    }

7.确保 mock 上不会发生交互

@Test
    public void test7() {

        List mockOne = Mockito.mock(List.class);
        List mockTwo = Mockito.mock(List.class);
        List mockThree = Mockito.mock(List.class);

        // using mocks - only mockOne is interacted
        mockOne.add("one");

        verify(mockOne).add("one");

        // 验证没有调用过某个行为
        verify(mockOne, never()).add("two");

        // 验证两个mock之间没有发生交互
        verifyZeroInteractions(mockTwo, mockThree);
    }