
本文详解如何正确使用 Mockito 对含默认方法的泛型接口(如 XYZConverter<D, E>)编写可信赖的单元测试,重点说明不 mock 被测方法、合理 spy 接口实例、精准 stub 依赖方法等核心实践。
本文详解如何正确使用 mockito 对含默认方法的泛型接口(如 `xyzconverter
在 Java 中,为定义了默认方法的泛型接口编写单元测试时,一个常见误区是试图直接 mock 接口本身(如 spy(XYZConverter.class)),或错误地对默认方法进行 when(...).thenReturn(...) —— 这不仅无效(默认方法无法被 Mockito 直接 stub),还会导致 NullPointerException 或测试逻辑失真。
正确的策略是:将接口作为真实对象进行部分模拟(@Spy),仅对默认方法所依赖的抽象方法(如 createFrom(D))进行 stub;默认方法本身则通过 spy 实例调用并验证其行为。
以下是一个完整、可运行的测试示例(基于 JUnit 4 + Mockito 3+):
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.Spy;
import org.mockito.junit.MockitoJUnitRunner;
import java.util.List;
import java.util.Arrays;
import static org.junit.Assert.assertEquals;
import static org.mockito.Mockito.when;
@RunWith(MockitoJUnitRunner.class)
public class XYZConverterTest {
// ✅ 正确:使用 @Spy 创建接口的“部分模拟”实例
// 注意:需指定具体类型参数,不能使用原始类型
@Spy
XYZConverter<DomainClass, EntityClass> converter;
@Mock
DomainClass domainClass;
@Mock
EntityClass entityClass;
@Test
public void createFromDtos_returnsMappedEntityList() {
// ✅ 正确:stub 被默认方法内部调用的抽象方法
when(converter.createFrom(domainClass)).thenReturn(entityClass);
// ✅ 执行被测的默认方法(无需 mock!)
List<EntityClass> result = converter.createFromDtos(Arrays.asList(domainClass));
// ✅ 验证结果符合预期
assertEquals(List.of(entityClass), result);
}
}⚠️ 关键注意事项:
- 不可 mock 默认方法本身:when(converter.createFromDtos(...)) 是非法且无效的,因为 createFromDtos 是默认实现,不在 Mockito 的 stub 范围内;
- 必须提供具体类型实参:@Spy XYZConverter<DomainClass, EntityClass> 合法;而 @Spy XYZConverter(原始类型)会导致泛型擦除,使 spy 失效;
- 避免在测试类上声明泛型 <D, E>:如 class XYZConverterTest<D,E> 会干扰 Mockito 的类型推断和 spy 行为,应移除;
- 确保 DomainClass 和 EntityClass 是真实存在的类(非接口):若为接口,需用 @Mock 模拟其实例(如本例所示),但 converter 必须是 @Spy 的泛型接口实例;
- 推荐升级至 JUnit 5 + Mockito 5:使用 @ExtendWith(MockitoExtension.class) 替代 @RunWith,API 更简洁稳定。
总结而言,测试含默认方法的接口,本质是测试其组合逻辑——它依赖自身其他方法的行为。因此,只需 spy 接口、mock 其依赖的抽象方法输入输出,再调用默认方法断言结果,即可实现高覆盖率与高可信度的单元验证。

















