
本文介绍如何使用 mockito 对集合(特别是 set)中的每个对象进行 mock,并在调用目标方法后准确验证其内部方法是否被逐一执行,适用于 lombok 简化类结构的场景。
在单元测试中,若需验证某个方法是否对 Set 中的每个元素都执行了特定操作(如调用 bMethod()),关键在于:不能直接 mock 同一个对象多次加入 Set —— 因为 Mockito.mock(B.class) 创建的 mock 实例默认基于对象身份(identity)比较,而 HashSet 依赖 equals() 和 hashCode() 去重;若重复添加同一 mock,Set 实际只保留一个元素,导致验证失败。
正确的做法是:为 Set 中的每个逻辑元素创建独立的 mock 实例。以下是完整、可运行的 JUnit 5 + Mockito 测试示例(假设已引入 mockito-core 和 lombok):
import org.junit.jupiter.api.Test;
import org.mockito.Mockito;
import java.util.HashSet;
import java.util.Set;
import static org.mockito.Mockito.verify;
public class ATest {
@Test
public void givenAWithBSet_whenAMethodIsCalled_thenCallBMethodOnAllBs() {
// GIVEN: 创建包含多个独立 B mock 的 Set
Set bSet = new HashSet<>();
bSet.add(Mockito.mock(B.class)); // mock #1
bSet.add(Mockito.mock(B.class)); // mock #2
// 可按需添加更多(如循环生成)
A a = new A(bSet);
// WHEN: 执行被测方法
a.aMethod();
// THEN: 验证每个 mock 的 bMethod 恰好被调用一次
for (B b : a.getBSet()) {
verify(b).bMethod(); // 等价于 verify(b, times(1)).bMethod()
}
}
}✅ 注意事项与最佳实践:
- 勿复用同一 mock 实例:bSet.add(mockB); bSet.add(mockB); 在 HashSet 中只会保留一个,导致 a.getBSet().size() 为 1,验证逻辑失效。
- 无需 verifyNoMoreInteractions:除非你严格要求 bMethod 是唯一被调用的方法,否则该断言易使测试脆弱;若需强约束,可保留,但建议仅在契约明确时使用。
- Lombok 兼容性良好:@Getter 和 @AllArgsConstructor 不影响 mock 行为,a.getBSet() 可安全访问原始 set 引用。
- 扩展性提示:若需模拟不同行为(如某次调用抛异常),可对特定 mock 使用 doThrow().when(mock).bMethod() 进行差异化配置。
通过为每个集合元素创建独立 mock,你既能保持测试的纯粹性(不依赖 B 的真实实现),又能精准验证迭代逻辑的完整性——这正是单元测试“隔离性”与“可验证性”的核心体现。
立即学习“Java免费学习笔记(深入)”;










