本文介绍如何对包含set字段的类a进行单元测试,通过mockito为集合中每个b对象创建独立mock实例,并准确验证bmethod()被逐一调用,避免因set去重机制导致的验证失败。
在使用Mockito对集合类型(尤其是Set)中的对象进行Mock时,一个常见误区是试图复用同一个Mock对象多次添加到Set中——这会导致实际只存入一个元素,因为Mockito生成的Mock对象默认基于引用相等(==)实现equals()和hashCode(),而HashSet依赖这两个方法进行去重。因此,若写成 bSet.add(mockB); bSet.add(mockB);,Set中最终仅保留一个元素,后续遍历验证就会漏掉调用断言。
正确的做法是:为Set中每个逻辑上独立的B实例创建独立的Mock对象。以下是完整、可运行的JUnit 5 + Mockito 4+ 测试示例:
import static org.mockito.Mockito.*;
import static org.junit.jupiter.api.Assertions.*;
import java.util.HashSet;
import java.util.Set;
import org.junit.jupiter.api.Test;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
class ATest {
@Test
void givenAWithBSet_whenAMethodIsCalled_thenCallBMethodOnAllBs() {
// GIVEN: 创建多个独立的B Mock实例(避免Set去重)
Set bSet = new HashSet();
bSet.add(mock(B.class)); // Mock #1
bSet.add(mock(B.class)); // Mock #2
bSet.add(mock(B.class)); // Mock #3(可按需扩展)
A a = new A(bSet);
// WHEN: 执行被测方法
a.aMethod();
// THEN: 验证每个Mock的bMethod恰好被调用1次
for (B b : a.getBSet()) {
verify(b, times(1)).bMethod();
}
// 可选:确保无其他意外调用
for (B b : a.getBSet()) {
verifyNoMoreInteractions(b);
}
}
}
✅ 关键要点说明: