mockito:使用最顺手的Mock框架

举报
大数据皮皮熊 发表于 2023/06/24 21:35:49 2023/06/24
【摘要】 Mockito 是一个 Java 单元测试框架,它能够帮助开发人员更轻松地进行单元测试。

一、Mockito 简介

1、Mockito 是什么?

Mockito 是一个 Java 单元测试框架,它能够帮助开发人员更轻松地进行单元测试。Mockito 最初由 OpenMind 公司开发,并于 2008 年发布第一个版本。

Mockito 的主要用途是模拟对象,即在测试过程中可以使用一个虚拟的对象来替换实际的对象。通过使用 Mockito,可以在测试过程中轻松地模拟各种情况,以便更好地测试代码。

Mockito 的主要特点包括:

  • 易于使用:Mockito 的 API 非常简单易懂,且易于使用。
  • 支持多种类型:Mockito 可以模拟多种类型的对象,包括抽象类、接口、基本类型和字符串等。
  • 功能强大:Mockito 提供了许多有用的工具类和方法,可以帮助开发人员更轻松地进行单元测试。
  • 跨平台:Mockito 可以在各种操作系统和硬件平台上运行,包括 Windows、Linux 和 macOS 等。

2、与其他Mock框架相比,mockito的特点

mockito与jacoco适配得比较好,且更新比较频繁,推荐实际业务开发中优先使用。

二、mockito推荐实践

基于官方文档优化:Mockito - mockito-core 4.11.0 javadoc

1、引入mockito

个人习惯mockito和jupiter搭配使用。

版本号推荐

<dependency>
    <groupId>org.mockito</groupId>
    <artifactId>mockito-inline</artifactId>
    <version>4.11.0</version>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>org.junit.jupiter</groupId>
    <artifactId>junit-jupiter</artifactId>
    <version>5.9.2</version>
    <scope>test</scope>
</dependency>

2、启动

习惯使用注解来新建mock对象。注意此时必须执行 MockitoAnnotations.openMocks(this);才能使注解生效。

@TestInstance(TestInstance.Lifecycle.PER_CLASS)
public class MockitoCase {
    @Mock
    LinkedList<String> mockedList;

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


3、验证

Mockito支持验证方法执行情况,比如:mockedList的add、clear操作均能验证。

注意:

  • 多次验证多次生效(幂等)
  • 未执行的操作不会生效
mockedList.add("one");
mockedList.clear();

Mockito.verify(mockedList).add("one");
Mockito.verify(mockedList).clear();
// 多次验证多次生效
Mockito.verify(mockedList).add("one");
//执行报错
// Mockito.verify(mockedList).add("two");

底层原理:// TBD

验证还支持其他复杂的方式,不过一般工作中jupiter就够用,这里我就不详细展开。


4、打桩(stub)

Mockito.when(mockedList.get(999)).thenReturn("element");
Assertions.assertEquals(mockedList.get(999), "element");

// 多次打相同桩后以最新的打桩结果为准
Mockito.when(mockedList.get(999)).thenReturn("element-new");
Assertions.assertEquals(mockedList.get(999), "element-new");

// 打桩异常
Mockito.doThrow(new RuntimeException()).when(mockedList).add("1");
Assertions.assertThrows(RuntimeException.class, ()-> mockedList.add("1"));

// 打桩多个返回结果
Mockito.when(mockedList.get(999)).thenReturn("element-999-1", "element-999-2", "element-999-3");
Assertions.assertEquals(mockedList.get(999), "element-999-1");
Assertions.assertEquals(mockedList.get(999), "element-999-2");
Assertions.assertEquals(mockedList.get(999), "element-999-3");

// 静态方法打桩
// public class Foo {
//     public static int bar(){
//         return 0;
//     }
// }
try (MockedStatic<Foo> mocked = Mockito.mockStatic(Foo.class)) {
    mocked.when(Foo::bar).thenReturn(1);
    Assertions.assertEquals(1, Foo.bar());
}

注意:

  • 异常打桩时,必须是可能会抛出的异常,不相关的异常执行时会报非法异常。

5、参数匹配

// mock 长度大于1的元素,存在在list中
Mockito.when(mockedList.contains(Mockito.argThat(s -> s.toString().length() > 1))).thenReturn(true);
Assertions.assertTrue(mockedList.contains("11"));
Assertions.assertFalse(mockedList.contains("1"));

Modifier and Type

Method

Description

static <T> T

any()

Matches anything, including nulls and varargs.

static <T> T

any(Class<T> type)

Matches any object of given type, excluding nulls.

static boolean

anyBoolean()

Any boolean or non-null Boolean

static byte

anyByte()

Any byte or non-null Byte.

static char

anyChar()

Any char or non-null Character.

static <T> Collection<T>

anyCollection()

Any non-null Collection.

static double

anyDouble()

Any double or non-null Double.

static float

anyFloat()

Any float or non-null Float.

static int

anyInt()

Any int or non-null Integer.

static <T> Iterable<T>

anyIterable()

Any non-null Iterable.

static <T> List<T>

anyList()

Any non-null List.

static long

anyLong()

Any long or non-null Long.

static <K,V>

anyMap()

Any non-null Map.

Map<K,V>

static <T> Set<T>

anySet()

Any non-null Set.

static short

anyShort()

Any short or non-null Short.

static String

anyString()

Any non-null String

static <T> T

argThat(ArgumentMatcher<T> matcher)

Allows creating custom argument matchers.

static boolean

booleanThat(ArgumentMatcher<Boolean> matcher)

Allows creating custom boolean argument matchers.

static byte

byteThat(ArgumentMatcher<Byte> matcher)

Allows creating custom byte argument matchers.

static char

charThat(ArgumentMatcher<Character> matcher)

Allows creating custom char argument matchers.

static String

contains(String substring)

String argument that contains the given substring.

static double

doubleThat(ArgumentMatcher<Double> matcher)

Allows creating custom double argument matchers.

static String

endsWith(String suffix)

String argument that ends with the given suffix.

static boolean

eq(boolean value)

boolean argument that is equal to the given value.

static byte

eq(byte value)

byte argument that is equal to the given value.

static char

eq(char value)

char argument that is equal to the given value.

static double

eq(double value)

double argument that is equal to the given value.

static float

eq(float value)

float argument that is equal to the given value.

static int

eq(int value)

int argument that is equal to the given value.

static long

eq(long value)

long argument that is equal to the given value.

static short

eq(short value)

short argument that is equal to the given value.

static <T> T

eq(T value)

Object argument that is equal to the given value.

static float

floatThat(ArgumentMatcher<Float> matcher)

Allows creating custom float argument matchers.

static int

intThat(ArgumentMatcher<Integer> matcher)

Allows creating custom int argument matchers.

static <T> T

isA(Class<T> type)

Object argument that implements the given class.

static <T> T

isNotNull()

Not null argument.

static <T> T

isNotNull(Class<T> type)

Not null argument.

static <T> T

isNull()

null argument.

static <T> T

isNull(Class<T> type)

null argument.

static long

longThat(ArgumentMatcher<Long> matcher)

Allows creating custom long argument matchers.

static String

matches(String regex)

String argument that matches the given regular expression.

static String

matches(Pattern pattern)

Pattern argument that matches the given regular expression.

static <T> T

notNull()

Not null argument.

static <T> T

notNull(Class<T> type)

Not null argument.

static <T> T

nullable(Class<T> clazz)

Argument that is either null or of the given type.

static <T> T

refEq(T value, String... excludeFields)

Object argument that is reflection-equal to the given value with support for excluding selected fields from a class.

static <T> T

same(T value)

Object argument that is the same as the given value.

static short

shortThat(ArgumentMatcher<Short> matcher)

Allows creating custom short argument matchers.

static String

startsWith(String prefix)

String argument that starts with the given prefix.

6、spy

在Mockito中,Mock对象和Spy对象都可以用来模拟对象,但它们之间有一些区别。

Mock对象是一个完全虚构的对象,它没有任何实际的行为。我们通常使用Mock对象来替代一些外部依赖以避免测试过程中对这些依赖的真实调用,从而隔离被测试代码的行为。

而Spy对象则是一个真实的对象,它可以记录自己的调用情况。在某些情况下,我们希望模拟一个对象的部分行为(例如模拟一个库函数的某个部分),同时保留它的其它行为。这时,Spy对象就比Mock对象更适合使用了。

具体来说,当我们使用Spy对象时,Mockito会创建一个真实的对象,并将其部分方法模拟出来,其他方法仍然保持原始行为。这意味着我们可以对Spy对象的一部分方法进行模拟(例如返回一个预定值),同时在需要时调用原始实现。

需要注意的是,由于Spy对象是一个真实的对象,因此需要保证它的状态不被改变,以保证测试结果的准确性。如果我们在使用Spy对象时修改了它的状态,那么在后续测试中可能会产生不可预测的结果。

List<Integer> list = new LinkedList<>();
List<Integer> spy = Mockito.spy(list);

// spy 面对mock打桩不生效,会抛异常IndexOutOfBoundsException,如
// Mockito.when(spy.get(0)).thenReturn(1);
// 必须使用doReturn才能打桩
Mockito.doReturn(1).when(spy).get(0);
Assertions.assertEquals(1, spy.get(0));


【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。