mockito:使用最顺手的Mock框架
一、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推荐实践
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. |
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. |
anyIterable() |
Any non-null Iterable. |
|
anyList() |
Any non-null List. |
|
static long |
anyLong() |
Any long or non-null Long. |
static <K,V> |
anyMap() |
Any non-null Map. |
anySet() |
Any non-null Set. |
|
static short |
anyShort() |
Any short or non-null Short. |
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. |
contains(String substring) |
String argument that contains the given substring. |
|
static double |
doubleThat(ArgumentMatcher<Double> matcher) |
Allows creating custom double argument matchers. |
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. |
matches(String regex) |
String argument that matches the given regular expression. |
|
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. |
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));
- 点赞
- 收藏
- 关注作者
评论(0)