Java测试中Mockito模拟PromoCodeService遇空指针异常的解决咨询
问题分析与解决方案
你遇到的promoCodeService为null的问题,核心是Mock对象没有正确注入到BusterClient实例中,同时你手动通过无参构造创建BusterClient,导致依赖的服务无法被初始化。以下是正确的Mock和测试方式:
修正后的测试代码(JUnit 5示例)
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; import java.lang.reflect.Method; import java.util.Optional; import static org.junit.jupiter.api.Assertions.*; import static org.mockito.Mockito.*; @ExtendWith(MockitoExtension.class) public class BusterClientTest { // 用@Mock注解创建PromoCodeService的Mock实例 @Mock private PromoCodeService promoCodeService; // 用@InjectMocks让Mockito自动将Mock注入到BusterClient中 // 无需手动new实例,Mockito会通过带参构造完成注入 @InjectMocks private BusterClient busterClient; @Test public void testTrackedReferralNotMatchingPromoCode() throws Exception { // 1. 配置Mock的返回值 when(promoCodeService.findByCampaignPromoCodeIds(12L, "test")) .thenReturn(Optional.of(PromoCode.builder().id(1L).build())); // 2. 准备测试用的CustomerRegistrationEvent实例(Mock必要方法) CustomerRegistrationEvent event = mock(CustomerRegistrationEvent.class); when(event.hasPromoCode()).thenReturn(true); when(event.getPromoCode()).thenReturn("test"); // 确保getCampaignIdAsLong方法能从event拿到12L(根据实际实现调整) when(event.getCampaignId()).thenReturn("12"); // 3. 反射调用私有方法 Method method = BusterClient.class.getDeclaredMethod("getPromoCode", CustomerRegistrationEvent.class); method.setAccessible(true); Optional<PromoCode> result = (Optional<PromoCode>) method.invoke(busterClient, event); // 4. 验证结果与Mock调用 assertTrue(result.isPresent()); assertEquals(1L, result.get().getId()); verify(promoCodeService).findByCampaignPromoCodeIds(12L, "test"); } }
关键修正点说明
启用Mockito注解支持
- JUnit 5用
@ExtendWith(MockitoExtension.class),JUnit 4用@RunWith(MockitoJUnitRunner.class),确保Mockito能处理@Mock和@InjectMocks注解。
- JUnit 5用
正确注入Mock对象
- 用
@Mock声明PromoCodeService的Mock实例,替代手动mock(PromoCodeService.class)。 @InjectMocks无需手动创建BusterClient实例,Mockito会自动调用带参构造BusterClient(PromoCodeService),将Mock注入进去。
- 用
完善测试前置条件
- 必须Mock
CustomerRegistrationEvent的必要方法(如hasPromoCode()、getPromoCode()),确保私有方法getPromoCode能走到调用promoCodeService的分支。
- 必须Mock
额外建议
- 尽量避免直接测试私有方法,建议测试调用该私有方法的公有业务方法,更符合黑盒测试的设计原则。
- 如果必须测试私有方法,可使用
PowerMock的Whitebox.invokeMethod简化反射代码,减少样板代码。
内容的提问来源于stack exchange,提问作者Peter Penzov
相关产品推荐
相关产品推荐

