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数据,减少工作量。
相关推荐
许彰午3 天前
39_Java单元测试JUnit入门
java·junit·单元测试
果子耶耶3 天前
让大模型帮我写单元测试,5个模型的覆盖率和边界处理能力实测
chatgpt·单元测试
川石课堂软件测试4 天前
APP自动化测试|高级手势操作&toast操作
css·功能测试·测试工具·microsoft·fiddler·单元测试·harmonyos
Thecozzy6 天前
单元测试 vs 手工测试:以水印功能为例
单元测试
HLAIA光子7 天前
AI Coding框架,打好TDD和SDD这两拳
单元测试·ai编程·代码规范
霸道流氓气质7 天前
Java 单元测试生成大量 Excel 测试数据实战指南
java·单元测试·excel
川石课堂软件测试7 天前
UI自动化测试|下拉选择框&弹出框&滚动条操作实践
开发语言·python·jmeter·ui·docker·单元测试·harmonyos
川石课堂软件测试8 天前
UI自动化测试|元素操作&浏览器操作实践
功能测试·测试工具·mysql·ui·docker·容器·单元测试
无聊的老谢8 天前
电信系统中的单元测试策略:构建高可靠性的微服务防线
数据库·微服务·单元测试