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 天前
WS63 嵌入式 SSD1306 OLED 驱动单元测试实战
单元测试·log4j
CesareCheung3 天前
高级软件测试工程师面试锦集
面试·单元测试·压力测试
2501_915918414 天前
在 Xcode 中运行和调试单元测试的完整指南
ide·vscode·macos·ios·单元测试·个人开发·xcode
极小狐5 天前
MR 里测试摘要空白、覆盖率不显示?JUnit 与覆盖率配置 9 步排查
数据库·ci/cd·junit·单元测试·mr·devops·代码覆盖率
toooooop85 天前
FastAdmin(ThinkPHP 5.0)单元测试实践:从零到跑通
单元测试·fastadmin
silvamux_5 天前
大模型 API 单元测试怎么 mock 不误伤
单元测试·log4j·php
Helix2505 天前
Python单元测试实战:pytest框架从入门到企业级测试体系搭建指南
python·单元测试·实战·mock·pytest·测试覆盖率·fixture
2302_805771076 天前
Day24:DDT+EXCEL数据驱动
功能测试·单元测试·自动化·测试用例·需求分析·web自动化
孟陬7 天前
不用盲调性能参数 Vitest 5.0 新推出 `vitest doctor` 一键诊断测试慢卡点,自动给出最优提速配置
性能优化·单元测试·vite
网络毒刘11 天前
端到端:用 Cursor Agent 完成「小功能 + 单测 + PR 描述」并附人工验收清单
单元测试·agent·ai编程·cursor·工具实践