Mockito 测试实战总结

最近公司要求补充测试用例,正好借这个机会学习下mockito,记录下加深下记忆。

以下测试都是用的testng

1. 基本使用

java 复制代码
public class MyTest {
    @Test
    public void test() {
        final MockTest mockTest = Mockito.mock(MockTest.class);
        when(mockTest.get()).thenReturn("b");
        assertEquals(mockTest.get(), "b");
    }

    @Test
    public void test2() {
        assertNull(mockTest.get());
    }

    public static class MockTest {
        public String get() {
            return "a";
        }
    }
}

2. 注解

使用注解必须在使用前调用 MockitoAnnotations.openMocks(this);, 该方法最后也会调用 Mockito 中的方法。相关类 MockAnnotationProcessor SpyAnnotationEngine等。

mockito 自带注解

1. @Mock-mock 一个类,当调用该类中的方法时,都不会产生实际的调用

java 复制代码
public class MyTest {
    @Mock
    private MockTest mockTest;

    @BeforeClass
    public void before(){
        MockitoAnnotations.openMocks(this);
    }

    @Test
    public void test() {
        when(mockTest.get()).thenReturn("b");
        assertEquals(mockTest.get(), "b");
    }

    public static class MockTest {
        public String get() {
            return "a";
        }
    }
}

2. @Spy - 和 @Mock 类似,但是正好相反,该类的方法就会产生实际的调用

java 复制代码
public class MyTest1 {
    @Spy
    private MockTest mockTest;

    @BeforeClass
    public void before() {
        MockitoAnnotations.openMocks(this);
    }

    @Test
    public void test() {
        assertEquals(mockTest.get(), "a");
    }

    @Test
    public void test2() {
        when(mockTest.get()).thenReturn("b");
        assertEquals(mockTest.get(), "b");
    }

    public static class MockTest {
        public String get() {
            return "a";
        }
    }
}

注解版本和 @Mock 类似。

3. @InjectMocks - 产生一个真实的实例,并且会注入 @Mock 和 @Spy 的类。

typescript 复制代码
public class MyTest2 {
    @InjectMocks
    private MockTest mockTest;
    @Mock
    private InjectMockObj injectMockObj;
    @Spy
    private InjectSpybj injectSpybj;

    @BeforeClass
    public void before() {
        MockitoAnnotations.openMocks(this);
    }

    @Test
    public void test() {
        assertNull(mockTest.get());
    }

    @Test
    public void test2() {
        when(injectMockObj.get()).thenReturn("a");
        assertEquals(mockTest.get(), "a");
    }

    @Test
    public void test3() {
        assertEquals(mockTest.getSpy(), "a");
    }

    public static class MockTest {
        private InjectMockObj injectMockObj;
        private InjectSpybj injectSpybj;

        public String get() {
            return injectMockObj.get();
        }
        public String getSpy() {
            return injectSpybj.get();
        }
    }

    public static class InjectMockObj {
        public String get() {
            return "a";
        }
    }

    public static class InjectSpybj {
        public String get() {
            return "a";
        }
    }
}

4. @Captor

配合 verify 捕获参数。

typescript 复制代码
public class MyTest3 {
    @Mock
    private MockTest mockTest;
    @Captor
    private ArgumentCaptor<String> captor;

    private AutoCloseable closeable;

    @BeforeClass
    public void open() {
        closeable = MockitoAnnotations.openMocks(this);
    }

    @AfterClass
    public void release() throws Exception {
        closeable.close();
    }

    @Test
    public void shouldDoSomethingUseful() {
        mockTest.set("b");
        verify(mockTest).set(captor.capture());
        assertEquals("b", captor.getValue());
    }

    public static class MockTest {
        public String set(String a) {
            return "a";
        }
    }
}

Spring Boot 中的注解

@MockBean @SpyBean

和 @Mock @Spy 类似,只是多了一个步骤,会把生成的类替换掉 ApplicationContext 中的类。

常用方法

  1. when(..).thenReturn(..)
  2. doReturn(..).doReturn().when(..).doStuff()

注意在一个方法上可以打两个桩然后有不同的操作,当调用时也会有不同的操作

csharp 复制代码
public class MyTest4 {
    @Mock
    private MockTest mockTest;

    @BeforeClass
    public void before(){
        MockitoAnnotations.openMocks(this);
    }


    @Test
    public void test() {
        doReturn("b").doReturn("z").when(mockTest).get();
        assertEquals(mockTest.get(), "b");
        assertEquals(mockTest.get(), "z");
    }

    @Test
    public void test1() {
        assertNull(mockTest.get());
    }

    public static class MockTest {
        public String get() {
            return "a";
        }
    }
}

参数匹配

只有当调用的方法的参数和类型和数量匹配时才能触发打桩点。

  1. ArgumentMatchers.any() 匹配任何参数
  2. ArgumentMatchers.anyString() 匹配任务字符串
  3. ArgumentMatchers.anyInt() 匹配任何Integer值
  4. ArgumentMatchers.eq() 匹配某个值
  5. 等等

总结

在使用了几天的 Mockito 之后,我的感受:

  1. 可以自定义的控制外部依赖对于测试的影响,当外部请求比较复杂时,可以使用 Mockito 来 mock 数据,而无需真正的去调用外部请求。
  2. 无需自己创建mock数据,减少工作量。
相关推荐
不要再敲了5 天前
掌握单元测试的利器:JUnit 注解从入门到精通
junit·单元测试
噔噔噔噔@6 天前
BUG排查流程
单元测试
云动雨颤9 天前
Python单元测试入门:3个核心断言方法,帮你快速定位代码bug
python·单元测试
Suresoft China9 天前
软件测试|STATIC 代码静态验证工具 C/C++ 工具链设置指南
c++·单元测试·静态测试·测试覆盖率·static·代码覆盖率·工具链设置
itppxie10 天前
Simulink中使用Test sequence单元测试
单元测试
泛联新安11 天前
如何根据项目需求选择合适的软件测试工具?iUnit智能单元测试平台提供专业化解决方案
c++·测试工具·单元测试
EndingCoder11 天前
单元测试:Jest 与 Electron 的结合
javascript·electron·单元测试·前端框架
奔跑吧邓邓子12 天前
【Java实战㉖】深入Java单元测试:JUnit 5实战指南
java·junit·单元测试·实战·junit5
川石课堂软件测试12 天前
Oracle 数据库使用事务确保数据的安全
数据库·python·功能测试·docker·oracle·单元测试·prometheus