
本文讲解在 spring boot 服务中,当无法通过依赖注入获取第三方工具类(如 requestclient)时,如何通过工厂模式解耦对象创建逻辑,并结合 mockito 实现精准单元测试模拟。
本文讲解在 spring boot 服务中,当无法通过依赖注入获取第三方工具类(如 requestclient)时,如何通过工厂模式解耦对象创建逻辑,并结合 mockito 实现精准单元测试模拟。
在实际开发中,我们常需调用第三方 SDK 或封装好的 HTTP 客户端(如示例中的 RequestClient),但若直接在业务方法中使用 new RequestClient<>(...) 创建实例,会导致该对象无法被 Mockito 管理——因为 mock() 创建的模拟对象仅在测试上下文中存在,而 new 操作始终触发真实构造,绕过所有 Mock 机制。
✅ 正确做法:引入工厂层解耦实例创建
核心思想是将“对象创建”这一副作用从业务逻辑中抽离,交由 Spring 管理的组件(如 @Component 工厂)负责。这样既符合 IoC(控制反转)原则,又为测试提供可插拔的入口。
首先,定义一个受 Spring 管理的工厂类:
@Component
public class RequestClientFactory {
public <T> RequestClient<T> createRequestClient() {
return new RequestClient<>(new HttpClientFactory());
}
}接着,修改业务服务,通过 @Autowired 注入该工厂,并在方法内调用其创建实例:
@Service
class CorrectionService {
@Autowired
private RequestClientFactory requestClientFactory;
BookingDetails getData() {
RequestClient<BookingDetails> requestClient = requestClientFactory.createRequestClient();
ApiResponse<BookingDetails> apiResponse =
requestClient.send(bookingRequest, BookingDetails.class);
return apiResponse.getData();
}
}此时,CorrectionService 不再持有硬编码的 new 逻辑,而是依赖抽象的工厂接口,天然支持测试替换。
✅ 单元测试:Mock 工厂 + Mock 客户端双重模拟
在 JUnit 5 + Mockito 的测试类中,使用 @Mock 和 @InjectMocks 组合,精准控制依赖链:
@ExtendWith(MockitoExtension.class)
class CorrectionServiceTest {
@Mock
private RequestClientFactory requestClientFactory;
@Mock
private RequestClient<BookingDetails> mockRequestClient;
@InjectMocks
private CorrectionService correctionService;
@Test
void testGetDataReturnsExpectedData() {
// 1. 配置工厂返回模拟客户端
when(requestClientFactory.createRequestClient())
.thenReturn(mockRequestClient);
// 2. 配置模拟客户端的行为
ApiResponse<BookingDetails> mockResponse = ApiResponse.<BookingDetails>builder()
.data(new BookingDetails("TEST-123"))
.build();
when(mockRequestClient.send(any(), eq(BookingDetails.class)))
.thenReturn(mockResponse);
// 3. 执行并断言
BookingDetails result = correctionService.getData();
assertThat(result).isNotNull();
assertThat(result.getBookingId()).isEqualTo("TEST-123");
}
}⚠️ 注意事项:
- 必须使用 @ExtendWith(MockitoExtension.class)(JUnit 5)或 MockitoJUnitRunner(JUnit 4)激活 Mockito 注解支持;
- when(...).thenReturn(...) 中的参数匹配要严谨:eq(BookingDetails.class) 比 any(Class.class) 更安全,避免因泛型擦除导致匹配失效;
- 若 RequestClient 是 final 类或含 final 方法,需启用 Mockito Inline Mock Maker(添加 mockito-inline 依赖);
- 切勿尝试对 new 出的对象做 mock() 后期望其生效——这是常见误区,根源在于 Java 对象生命周期不可干预。
✅ 总结
模拟第三方库的关键不在于“强行拦截 new”,而在于提前设计可测试性。通过工厂模式将对象创建委托给 Spring 容器,即可自然实现运行时替换与测试隔离。这种重构成本低、收益高,是保障微服务单元测试覆盖率与可靠性的基石实践。

















