
在 junit 测试中,当被测类直接调用返回 void 的 `s3client.deleteobject()` 方法时,不能使用 `when(...).thenreturn(...)`,而应改用 `donothing().when(...).method()` 进行行为模拟,从而安全跳过该行执行。
在使用 Mockito 对 AWS SDK(如 AmazonS3)进行单元测试时,一个常见误区是试图对 void 方法使用 when().thenReturn() 语法。由于 deleteObject(DeleteObjectRequest) 是一个无返回值方法(即返回类型为 void),Mockito 的 when() API 无法为其建立 stub —— 它专为有返回值的方法设计,因此编译器会报错:
error: no instances of type variable T exist so that void conforms to T
✅ 正确做法是使用 doNothing() 配合 when() 的变体语法(即 doNothing().when(mock).voidMethod()),它专为 void 方法设计,用于声明“调用该方法时不执行任何操作”。
✅ 正确的 Mockito 写法如下:
// 创建 mock 实例
AmazonS3 s3Client = mock(AmazonS3.class);
// 告诉 Mockito:当 deleteObject 被任意 DeleteObjectRequest 调用时,什么也不做
doNothing()
.when(s3Client)
.deleteObject(any(DeleteObjectRequest.class));⚠️ 注意事项:
- doNothing() 是 doAnswer() / doThrow() / doReturn() 系列 API 的一员,必须搭配 when(mock).method() 的链式调用形式(注意括号位置和顺序),不可写成 when(s3Client.deleteObject(...)).doNothing()(这是错误的)。
- 确保 s3Client 实例已正确注入到 MyClass 中(例如通过构造函数或 setter 注入),否则 mock 将不生效。
- 若 s3Client 是私有字段且未提供注入点,需配合 @InjectMocks + @Mock 使用 PowerMockito(不推荐)或重构为可测试设计(更推荐)。
? 完整测试示例(JUnit 5 + Mockito 4+):
class MyClassTest {
@Mock
private AmazonS3 s3Client;
@InjectMocks
private MyClass myClass; // 假设 MyClass 构造函数或字段接受 AmazonS3
@BeforeEach
void setUp() {
MockitoAnnotations.openMocks(this);
}
@Test
void myMethod_deletesObjectInS3_whenCalled() {
// Arrange
doNothing()
.when(s3Client)
.deleteObject(any(DeleteObjectRequest.class));
// Act
myClass.myMethod("test-bucket", "path/to/object");
// Assert(可选:验证是否确实调用了该方法)
verify(s3Client).deleteObject(argThat(req ->
"test-bucket".equals(req.getBucketName()) &&
"path/to/object".equals(req.getKey())
));
}
}? 总结:对 void 方法打桩,请始终优先使用 doNothing().when(mock).method();避免 when(mock.method()).thenReturn(...)(编译失败)或 when(mock.method()).thenThrow(...)(语法非法)。这是 Mockito 的核心约定,也是编写可靠、可维护单元测试的关键实践。
立即学习“Java免费学习笔记(深入)”;










