目录
- Mockito
- Mockito使用
- Mockito依赖
- Mockito常用注解
- Mockito常用方法
Mockito
Mockito 是一个流行的 Java 单元测试框架,用于模拟(mock)对象以便进行单元测试。它可以帮助开发人员创建和管理模拟对象,以便在测试过程中替换那些不容易构造或获取的对象,从而达到测试被测代码的行为,而无需依赖于实际的外部系统或服务。
Mockito 的主要特点包括:
-
模拟对象:Mockito 允许创建模拟对象,这些模拟对象具有与真实对象相似的行为,但实际上只是虚拟的对象实例。通过模拟对象,可以模拟外部依赖、交互行为等,从而使测试更加独立和可控。
-
验证行为:Mockito 提供了丰富的 API 来验证模拟对象的交互行为,例如方法是否被调用、调用次数、参数匹配等。通过验证行为,可以确保被测代码按预期执行了与外部系统的交互。
-
Stubbing 方法:Mockito 允许对模拟对象的方法进行 Stubbing,即定义当调用某个方法时应该返回的值。这样可以模拟不同的场景和条件,以覆盖多种测试情况。
-
灵活性:Mockito 提供了简洁且易于使用的 API,支持与 JUnit、TestNG 等测试框架集成。同时,它还提供了丰富的功能和扩展,可以满足各种测试场景的需求。
Mockito使用
Mockito依赖
SpringBoot默认的Mock框架是Mockito,和junit一样,只需要依赖spring-boot-starter-test就可以了
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope>
</dependency>
如果是单独添加依赖,那么添加下面依赖
<dependency><groupId>org.mockito</groupId><artifactId>mockito-core</artifactId><version>{mockito_version}</version></dependency><dependency><groupId>org.mockito</groupId><artifactId>mockito-junit-jupiter</artifactId><version>{mockito_version}</version></dependency>
mockito-core:Mockito 核心依赖,提供了 Mockito 框架的核心功能和 API。
mockito-junit-jupiter:Mockito 与 JUnit Jupiter 的集成依赖,用于在 JUnit 5 环境下使用 Mockito 进行单元测试。
如果需要使用内联Mocks,那么还需要添加下面这个依赖
mockito-inline:Mockito 的内联依赖,用于支持内联(inline)Mocks 的创建和使用。
Mockito常用注解
@RunWith
@RunWith注解用于在JUnit测试中指定运行器(Runner),常用的有以下两种
@RunWith(MockitoJUnitRunner.class)
:@RunWith(MockitoJUnitRunner.class)
是Mockito框架提供的JUnit运行器,用于运行使用Mockito进行单元测试的类。- 当使用
@RunWith(MockitoJUnitRunner.class)
注解一个测试类时,Mockito会自动初始化这个类中使用@Mock
、@InjectMocks
等注解创建的模拟对象。 - 这样可以简化测试类的设置过程,使得在测试中可以直接使用模拟对象而不需要手动初始化。
@RunWith(MockitoJUnitRunner.class)
public class SomeTestClass {@Mockprivate SomeService someService;// Test methods using mock objects
}
@RunWith(SpringRunner.class)
:@RunWith(SpringRunner.class)
是Spring Framework提供的JUnit运行器,用于运行基于Spring的集成测试。- 当使用
@RunWith(SpringRunner.class)
注解一个测试类时,Spring会加载应用程序上下文,并可以通过@Autowired
等注解注入Spring管理的Bean。 - 这样可以进行更真实的集成测试,包括与数据库、外部服务的交互等。
@RunWith(SpringRunner.class)
@SpringBootTest
public class SpringIntegrationTest {@Autowiredprivate SomeService someService;// Integration test methods using Spring context
}
注:如果是在Spring Boot项目中,使用了@SpringBootTest注解,就不需要再额外使用@RunWith注解了。因为在Spring Boot中,@SpringBootTest注解用于创建一个完整的应用程序上下文,这样你就可以在测试中使用所有的Spring Beans和自动配置。这个注解本身就包含了@RunWith(SpringRunner.class)的功能,因此你不需要显式地添加@RunWith注解。
@Test
标记测试方法,被 @Test 注解标记的方法会被 JUnit 的运行器执行,作为测试方法进行测试。
@MockBean
模拟Spring Boot应用程序中Spring上下文的对象,@MockBean是Spring Boot测试框架的一部分(属于spring-boot-test包),@MockBean注解的类将替代Spring容器中同类型的类。如果同类型的类不存在,@MockBean会自动定义并添加它。对于不是bean的依赖,@MockBean会将它模拟成bean并与存在的依赖一起添加到上下文中。在Spring Boot的测试类中,@MockBean通常与@SpringBootTest和@AutoConfigureMockMvc等注解一起使用。
在Spring Boot的测试类中,通常更倾向于使用@MockBean来模拟对象,因为它与Spring Boot的测试框架有更好的集成。
@Mock
创建一个模拟对象,并注入到测试类中。通常和 @InjectMocks 注解一起使用,用于为测试类中的被测对象注入模拟对象。当你使用 @Mock 注解一个对象时,Mockito 会为你创建一个该对象的模拟实例。这个模拟实例的行为(即方法的返回值和它们被调用的方式)可以被精确地控制和验证。默认情况下,模拟对象上的所有方法调用都会返回 null(对于引用类型)或默认值(对于原始类型)。你可以使用 when(…).thenReturn(…)、when(…).thenThrow(…) 等 Mockito 方法来定义模拟对象的行为。
@Spy
用于创建一个部分模拟对象,与@Mock不同,@Spy创建的是一个实际对象的代理,并且允许你选择性地模拟对象中的某些方法。默认情况下,所有未被特别模拟的方法都会调用实际对象的方法,
通常与doReturn/doThrow等方法结合使用。
@Captor
用于捕获方法参数,以便验证方法调用参数是否正确。
@InjectMocks
注入被测对象,并自动将 @Mock 和 @Spy 标注的对象注入到被测对象中。
public class SomeTestClass {@Mockprivate SomeService someService;@InjectMocksprivate SomeController someController;}
@Before 和 @After
JUnit 提供的注解,在每个测试方法执行之前和之后分别执行一段代码。通常用于设置测试的前置条件或进行资源的清理工作。
public class SomeTestClass {@Beforepublic void setUp() {// Set up test data or initialize resources}@Afterpublic void tearDown() {// Clean up resources}@Testpublic void testSomeMethod() {// Test method}
}
Mockito常用方法
Mockito.when()
Mockito.when() 是 Mockito 框架中的一个方法,用于设置模拟对象的方法调用行为。它通常与 thenReturn()、thenThrow() 或 thenAnswer() 方法一起使用。
Mockito.when(mock.methodCall()).thenReturn(value) 的语法表示当模拟对象的 methodCall() 方法被调用时,应该返回指定的 value 值。
下面是 Mockito.when() 方法的一些常见用法:
- 返回固定值:
使用thenReturn返回一个固定值,如果返回多个值,使用逗号分隔
// 当 getUserById() 方法被调用时,返回一个预先定义的 User 对象
Mockito.when(userServiceMock.getUserById(1)).thenReturn(new User("Alice"));// 第一次调用 getUserById() 返回 Alice,第二次调用返回 Bob
Mockito.when(userServiceMock.getUserById(1)).thenReturn(new User("Alice")).thenReturn(new User("Bob"));
- 抛出异常
使用thenThrow可以抛出一个指定的异常
Mockito.when(userServiceMock.saveUser(null)).thenThrow(new IllegalArgumentException("Invalid parameter"));
- 使用 Answer 接口自定义行为
使用thenAnswer方法,传入Answer接口的实现类,就可以实现自定义返回
// 根据输入参数计算结果并返回
Mockito.when(calculatorMock.calculate(Mockito.anyInt(), Mockito.anyInt())).thenAnswer(invocation -> {int a = invocation.getArgument(0);int b = invocation.getArgument(1);return a + b;
});
Mockito.mock(Class classToMock)
用于创建一个指定类的模拟对象
Mockito.doReturn()
Mockito.doReturn() 用于设置模拟对象方法的返回值。与 Mockito.when().thenReturn() 方法类似,Mockito.doReturn() 也用于模拟方法调用时的返回结果,但在某些特定情况下会更加灵活和有效。
以下是 Mockito.doReturn() 方法的一些常见用法:
- 设置模拟对象方法的返回值:
// 使用 doReturn() 设置 getUserById() 方法的返回值
Mockito.doReturn(new User("Alice")).when(userServiceMock).getUserById(1);
- 处理 void 方法的行为:
// 设置 delete() 方法为无返回值时的行为
Mockito.doNothing().when(userServiceMock).deleteUser(1);// 设置 void 方法抛出异常时的行为
Mockito.doThrow(new RuntimeException("Unable to delete user")).when(userServiceMock).deleteUser(2);
Mockito.verify():
Mockito.verify() 用于验证模拟对象的方法是否被调用以及调用的次数。它通常与 times()、atLeastOnce()、never() 等方法一起使用。
Mockito.verify(mock, times(n)).methodCall() 的语法表示验证模拟对象的 methodCall() 方法被调用了 n 次。
以下是 Mockito.verify() 方法的一些常见用法:
- 验证方法是否被调用:
verify(mock): 验证模拟对象的方法至少被调用了一次。这是 verify 的默认行为。
Mockito.verify(userServiceMock).getUserById(1);
- 验证方法调用次数:
verify(mock, times(n)): 验证模拟对象的方法被调用了指定次数。
// 验证 getUserById() 方法被调用了两次
Mockito.verify(userServiceMock, times(2)).getUserById(1);// 验证 saveUser() 方法至少被调用了一次
Mockito.verify(userServiceMock, atLeastOnce()).saveUser(Mockito.any(User.class));// 验证 deleteUser() 方法从未被调用
Mockito.verify(userServiceMock, never()).deleteUser(2);
Mockito.any(Class type)
Mockito.any(Class type) 用于创建一个匹配任意指定类型的参数的匹配器。在设置模拟对象方法的行为时,我们经常会使用 Mockito.any() 来匹配任意参数。
下面是 Mockito.any() 方法的一些常见用法:
// 当 saveUser() 方法的参数为任意对象,都返回 true
Mockito.when(userServiceMock.saveUser(Mockito.any())).thenReturn(true);// 当 saveUser() 方法的参数为任意 User 对象时,都返回 true
Mockito.when(userServiceMock.saveUser(Mockito.any(User.class))).thenReturn(true);// 当 calculate() 方法的两个参数为任意整数时,返回固定值 10
Mockito.when(calculatorMock.calculate(Mockito.anyInt(), Mockit.anyInt())).thenReturn(10);
Mockito.reset
Mockito.reset(mock):重置模拟对象的状态,清除之前的交互和验证。
Mockito.reset(userServiceMock);
Mockito.eq()
Mockito.eq() 用于创建一个匹配特定参数值的匹配器。当你想在模拟对象的方法调用中匹配一个特定的参数时,你可以使用 eq。它通常与 when 和 verify 等方法一起使用。
下面是 Mockito.eq() 方法的一些常见用法:
- 匹配特定参数值:
// 当 getUserById() 方法的参数为 1 时返回特定的结果
Mockito.when(userServiceMock.getUserById(Mockito.eq(1))).thenReturn(new User("Alice"));// 当 calculate() 方法的两个参数为特定整数时返回固定值 10
Mockito.when(calculatorMock.calculate(Mockito.eq(2), Mockito.eq(3))).thenReturn(10);
- 验证方法调用时特定参数值:
// 验证 deleteUser() 方法被调用时传入的参数为特定整数
Mockito.verify(userServiceMock).deleteUser(Mockito.eq(1));
在这个例子中,verify 方法会确保 userServiceMock.deleteUser方法被调用过,并且传递的参数是 1。如果没有这样的调用发生,或者传递了不同的参数,那么验证将会失败。
需要注意的是,eq 只能用于精确匹配。如果你想匹配任何参数(不关心实际值),你应该使用 any()。