如何在 Mockito 中模拟 void 方法:面向初学者的指南与示例

面向初学者的在线Python训练器

轻松学习Python,无需理论负担。在浏览器中直接解决带自动检查的实践任务,无需安装任何东西。

开始课程

引言:为什么 void 方法对初学者来说是难题?

\n\n

你是否曾用 Mockito 编写 Java 单元测试,却突然遇到了瓶颈?似乎一切都很简单:模拟对象,为那些有返回值的方法(字符串、数字、列表)配置行为。但一旦涉及到 void 方法——那些不返回任何值,只在内部执行某些操作的方法(例如,保存数据、发送邮件、记录操作)——你就会陷入困境。

\n\n

为什么?因为常用的 when(mock.someMethod()).thenReturn(something) 在这里不起作用。编译器根本不允许你写 when(mock.voidMethod()).thenReturn(...)——void 方法不返回任何值,thenReturn 在这里毫无意义。

\n\n

正是这个问题——"How to mock void methods with Mockito"——在 Stack Overflow 上获得了数千次浏览。今天,我们将一劳永逸地解决它。你将学会不仅如何模拟 void 方法,而且如何正确、优雅、无痛地做到这一点。

\n\n

我们开始吧!🚀

\n\n

从测试角度来看,什么是 void 方法?

\n\n

Void 方法是一种执行操作但不返回结果的方法。例如:

\n\n
public class EmailService {\n    public void sendWelcomeEmail(String email) {\n        // 这里是实际发送邮件\n        System.out.println("正在发送邮件至 " + email);\n    }\n}
\n\n

在实际项目中,我们不希望每次运行测试时都实际发送邮件。我们只需要 验证该方法是否被调用,或者 屏蔽其执行,或者 让它抛出异常(以测试错误处理)。

\n\n

为此,Mockito 提供了使用 doNothing()、doThrow()、doAnswer() 和 doCallRealMethod() 的特殊语法。

\n\n

1. 最常见的情况:doNothing() —— 仅屏蔽 void 方法

\n\n

如果你需要 void 方法在被调用时什么都不做——请使用 doNothing()。这是 Mockito 对 void 方法的默认行为,但有时显式指定是有用的(例如,为了可读性或在使用 spy 时)。

\n\n
import org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\nimport org.mockito.Mock;\nimport org.mockito.junit.jupiter.MockitoExtension;\n\nimport static org.mockito.Mockito.*;\n\n@ExtendWith(MockitoExtension.class)\npublic class EmailServiceTest {\n\n    @Mock\n    private EmailService emailService;\n\n    @Test\n    void testDoNothing() {\n        // 配置:调用 sendWelcomeEmail 时什么都不做\n        doNothing().when(emailService).sendWelcomeEmail(anyString());\n\n        // 调用方法\n        emailService.sendWelcomeEmail("test@example.com");\n\n        // 验证该方法确实被调用了\n        verify(emailService).sendWelcomeEmail("test@example.com");\n    }\n}
\n\n

重要提示: 如果你使用 @Mock,则无需编写 doNothing()——Mockito 默认将 void 方法视为“空操作”。但如果你使用 @Spy(间谍),则会调用真实方法,并且需要 doNothing() 来阻止这种情况。

\n\n

2. doThrow() —— 在 void 方法中模拟错误

\n\n

一个非常常见的任务:测试你的代码在邮件发送服务出错时的反应。为此,我们让 void 方法抛出异常。

\n\n
@Test\nvoid testDoThrow() {\n    // 配置:调用 sendWelcomeEmail 时抛出 RuntimeException\n    doThrow(new RuntimeException("邮件发送错误"))\n            .when(emailService).sendWelcomeEmail(anyString());\n\n    // 现在调用该方法时会抛出异常\n    assertThrows(RuntimeException.class, () -> {\n        emailService.sendWelcomeEmail("fail@example.com");\n    });\n\n                

博客

书籍推荐