TestArgumentCaptor.java

本文通过两个测试案例展示了如何使用 Mockito 的 ArgumentCaptor 功能来捕获方法调用参数,验证方法是否被正确调用。示例中创建了一个武器类 Weapon,该类有一个 fire 方法用于发射子弹列表。通过 ArgumentCaptor 捕获传递给 fire 方法的实际参数,并验证其内容。
import java.util.ArrayList;
import java.util.List;

import org.mockito.ArgumentCaptor;
import org.mockito.Captor;
import org.mockito.Mock;
import org.mockito.Spy;

import static org.mockito.Mockito.*;
import org.testng.annotations.Test;


public class TestArgumentCaptor extends BaseTeser{
    @Spy    
    private Weapon weapon;

    @Mock   
    private Weapon weapon1;

    @Captor
    private ArgumentCaptor<List<Bullet>> captor;

    //@Test
    public void test1(){
        List<Bullet> bullets = new ArrayList<Bullet>();
        bullets.add(new Bullet());
        bullets.add(new Bullet());

        weapon.fire(bullets);

        verify(weapon).fire(captor.capture());

        List<Bullet> list = captor.getValue();

        p(list.size());
    }

    @Test
    public void test2(){

        doCallRealMethod().when(weapon1).fire(anyList());

        List<Bullet> bullets = new ArrayList<Bullet>();
        bullets.add(new Bullet());
        bullets.add(new Bullet());

        weapon1.fire(bullets);

        verify(weapon1).fire(captor.capture());

        List<Bullet> list = captor.getValue();

        p(list.size());
    }
}
<think>在Mockito中模拟没有返回值(void返回类型)的方法时,我们需要使用`Mockito.doNothing()`、`Mockito.doThrow()`等方法来定义行为。以下是详细说明和代码示例。 ### 核心方法 Mockito提供以下方式处理void方法: 1. **`doNothing()`**:默认行为(什么都不做) 2. **`doThrow()`**:抛出指定异常 3. **`doAnswer()`**:执行自定义逻辑 4. **`doCallRealMethod()`**:调用真实方法(用于部分模拟) ### 代码示例 #### 场景1:模拟void方法不执行任何操作 ```java @Test void testDoNothing() { // 创建模拟对象 List<String> mockList = Mockito.mock(List.class); // 设置void方法的行为 Mockito.doNothing().when(mockList).clear(); // 调用方法 mockList.clear(); // 验证方法被调用 Mockito.verify(mockList).clear(); } ``` #### 场景2:模拟void方法抛出异常 ```java @Test void testDoThrow() { List<String> mockList = Mockito.mock(List.class); // 设置调用clear()时抛出异常 Mockito.doThrow(new RuntimeException("DB error")).when(mockList).clear(); // 验证异常抛出 assertThrows(RuntimeException.class, mockList::clear); } ``` #### 场景3:模拟void方法执行自定义逻辑 ```java @Test void testDoAnswer() { List<String> mockList = Mockito.mock(List.class); List<String> backupList = new ArrayList<>(); // 当调用addAll方法时,将参数保存到backupList Mockito.doAnswer(invocation -> { Collection<?> items = invocation.getArgument(0); backupList.addAll((Collection<String>)items); return null; // void方法返回null }).when(mockList).addAll(Mockito.anyCollection()); // 测试调用 mockList.addAll(Arrays.asList("A", "B")); // 验证自定义逻辑生效 assertEquals(Arrays.asList("A", "B"), backupList); } ``` #### 场景4:部分模拟(调用真实方法) ```java @Test void testDoCallRealMethod() { // 创建部分模拟对象(spy) List<String> realList = new ArrayList<>(); List<String> spyList = Mockito.spy(realList); // 默认会调用真实方法,但我们可以覆盖行为 Mockito.doNothing().when(spyList).clear(); spyList.add("Test"); spyList.clear(); // 这里不会真正清除列表 // 验证:列表实际未被清除 assertFalse(spyList.isEmpty()); } ``` ### 重要注意事项 1. **语法结构**:必须使用`doXxx().when(mock).method()`格式,不能使用`when(mock.method()).thenXxx()`(因为void方法不能作为参数) ```java // 错误写法(编译不通过) Mockito.when(mockList.clear()).thenThrow(RuntimeException.class); // 正确写法 Mockito.doThrow(RuntimeException.class).when(mockList).clear(); ``` 2. **默认行为**:对于void方法,Mockito默认会什么都不做(即`doNothing()`) 3. **验证调用**:使用`verify()`确认void方法是否被调用 ```java // 验证方法被调用1次 Mockito.verify(mockList, Mockito.times(1)).clear(); // 验证方法从未被调用 Mockito.verify(mockList, Mockito.never()).add("item"); ``` ### 高级用法:参数捕获 ```java @Test void testArgumentCaptor() { List<String> mockList = Mockito.mock(List.class); mockList.add("test"); // 创建参数捕获器 ArgumentCaptor<String> captor = ArgumentCaptor.forClass(String.class); // 捕获add方法的参数 Mockito.verify(mockList).add(captor.capture()); assertEquals("test", captor.getValue()); } ``` §§相关问题§§: 1. 如何在Mockito中模拟静态方法? 2. 使用Mockito验证方法调用次数有哪些方式? 3. Mockito的`@Spy`和`@Mock`注解有何区别? 4. 如何在Mockito中模拟带有参数的方法返回值?</think># Mockito 模拟无返回值(void)函数详解 在 Mockito 中模拟没有返回值的函数(void 方法)需要使用特殊的语法结构,因为标准的 `when().thenReturn()` 语法不适用于 void 方法。以下是完整的解决方案: ## 核心方法 ### 1. 使用 `doNothing()` 模拟无操作 ```java @Test void testDoNothing() { // 创建模拟对象 UserRepository mockRepo = Mockito.mock(UserRepository.class); // 模拟无返回值的 void 方法 Mockito.doNothing().when(mockRepo).clearCache(); // 调用方法 mockRepo.clearCache(); // 验证方法被调用 Mockito.verify(mockRepo).clearCache(); } ``` ### 2. 使用 `doThrow()` 模拟抛出异常 ```java @Test void testDoThrow() { UserRepository mockRepo = Mockito.mock(UserRepository.class); // 模拟方法抛出异常 Mockito.doThrow(new DatabaseException("Connection failed")) .when(mockRepo) .clearCache(); // 验证异常被抛出 assertThrows(DatabaseException.class, mockRepo::clearCache); } ``` ### 3. 使用 `doAnswer()` 执行自定义逻辑 ```java @Test void testDoAnswer() { UserRepository mockRepo = Mockito.mock(UserRepository.class); List<String> logs = new ArrayList<>(); // 模拟方法执行自定义逻辑 Mockito.doAnswer(invocation -> { logs.add("Cache cleared at " + System.currentTimeMillis()); return null; // void 方法返回 null }).when(mockRepo).clearCache(); // 调用方法 mockRepo.clearCache(); // 验证副作用 assertEquals(1, logs.size()); assertTrue(logs.get(0).contains("Cache cleared")); } ``` ### 4. 使用 `doCallRealMethod()` 调用真实实现 ```java @Test void testDoCallRealMethod() { // 创建 spy 对象(部分模拟) UserRepository realRepo = new UserRepositoryImpl(); UserRepository spyRepo = Mockito.spy(realRepo); // 模拟特定方法调用真实实现 Mockito.doCallRealMethod().when(spyRepo).clearCache(); // 调用方法 spyRepo.clearCache(); // 验证真实方法被调用 Mockito.verify(spyRepo).clearCache(); } ``` ## 完整示例:模拟服务层方法 ```java public class NotificationService { public void sendEmail(String address, String content) { // 实际发送邮件的实现 } } public class UserService { private final NotificationService notificationService; public UserService(NotificationService notificationService) { this.notificationService = notificationService; } public void registerUser(User user) { // 保存用户逻辑... notificationService.sendEmail(user.getEmail(), "Welcome!"); } } @ExtendWith(MockitoExtension.class) class UserServiceTest { @Mock private NotificationService mockNotificationService; @InjectMocks private UserService userService; @Test void testRegisterUserSendsEmail() { // 模拟 void 方法 Mockito.doNothing().when(mockNotificationService) .sendEmail(Mockito.anyString(), Mockito.anyString()); // 执行测试 User user = new User("test@example.com", "John Doe"); userService.registerUser(user); // 验证方法被调用 Mockito.verify(mockNotificationService) .sendEmail("test@example.com", "Welcome!"); } @Test void testRegisterUserHandlesEmailFailure() { // 模拟方法抛出异常 Mockito.doThrow(new EmailException("SMTP error")) .when(mockNotificationService) .sendEmail(Mockito.anyString(), Mockito.anyString()); User user = new User("test@example.com", "John Doe"); // 验证业务逻辑处理异常 assertDoesNotThrow(() -> userService.registerUser(user)); } } ``` ## 关键注意事项 1. **语法结构**:必须使用 `doXxx().when(mock).method()` 格式 ```java // 正确 Mockito.doNothing().when(mock).method(); // 错误(编译不通过) Mockito.when(mock.method()).then... ``` 2. **参数匹配**:可以使用参数匹配器 ```java Mockito.doNothing() .when(mockService) .process(Mockito.anyString(), Mockito.eq("important")); ``` 3. **调用次数验证**:验证方法调用情况 ```java // 验证方法被调用1次 Mockito.verify(mock, Mockito.times(1)).method(); // 验证方法从未被调用 Mockito.verify(mock, Mockito.never()).method(); // 验证方法至少调用2次 Mockito.verify(mock, Mockito.atLeast(2)).method(); ``` 4. **顺序验证**:验证方法调用顺序 ```java InOrder inOrder = Mockito.inOrder(mock1, mock2); inOrder.verify(mock1).firstMethod(); inOrder.verify(mock2).secondMethod(); ``` ## 与有返回值方法的对比 | 特性 | void 方法 | 有返回值方法 | |------|-----------|-------------| | 模拟语法 | `doNothing().when(mock).method()` | `when(mock.method()).thenReturn(value)` | | 异常模拟 | `doThrow(exception).when(mock).method()` | `when(mock.method()).thenThrow(exception)` | | 自定义行为 | `doAnswer().when(mock).method()` | `when(mock.method()).thenAnswer()` | | 调用真实方法 | `doCallRealMethod().when(mock).method()` | `when(mock.method()).thenCallRealMethod()` |
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值