调用Mock方法时出现NullPointerException的原因与修复方案
问题:Mock依赖后仍抛出NullPointerException
在调用CustomerProfileService的getCustomerProfile方法时,标注位置抛出NullPointerException,但测试中已经Mock了CustomerProfileRepository,请问原因及修复方法?
类定义
@Service("customer-profile-service") public class CustomerProfileService { CustomerProfileRepository customerProfileRepository; public CustomerProfileService(CustomerProfileRepository customerProfileRepository){ this.customerProfileRepository = customerProfileRepository; } public CustomerProfile getCustomerProfile(RestConsumerRequest<MortgPointsFulfillRequest> consumerRequest) { RestConnectorResponse<RestConsumerResponse<CustomerProfile>> restConnectorResponseC1 = customerProfileRepository.customerProfileLookup(consumerRequest); // <- NullPointerException ... } }
测试用例
@ExtendWith(MockitoExtension.class) public class CustomerProfileServiceTest { @Mock CustomerProfile customerProfile; @Mock RestConsumerRequest restConsumerRequest; @Mock CustomerProfileRepository customerProfileRepository; @Mock RestConnectorResponse<RestConsumerResponse<CustomerProfile>> restConnectorResponseC1; @Spy CustomerProfileService customerProfileService = new CustomerProfileService(customerProfileRepository); @Test public void getCustomerProfileTest() { doReturn(restConnectorResponseC1).when(customerProfileRepository).customerProfileLookup(restConsumerRequest); customerProfileService.getCustomerProfile(restConsumerRequest); Mockito.verify(customerProfileRepository, times(1)).customerProfileLookup(any()); } }
原因分析
泛型类型不匹配,Mock Stub未生效
服务方法的参数是RestConsumerRequest<MortgPointsFulfillRequest>,但测试中Mock的restConsumerRequest是无泛型的原始类型。Mockito的参数匹配会严格校验类型(包括泛型),导致你定义的doReturn(...)stub不触发,customerProfileLookup返回默认的null,进而抛出NPE。Spy初始化时机错误,依赖未正确注入
直接用@Spy注解手动创建CustomerProfileService实例时,Mockito可能还未完成customerProfileRepositoryMock对象的初始化,导致注入的依赖是未初始化的无效对象(甚至是null)。
修复方案
1. 修正泛型类型匹配
将测试中的RestConsumerRequest Mock改为带正确泛型的版本:
@Mock RestConsumerRequest<MortgPointsFulfillRequest> restConsumerRequest;
2. 正确初始化Service实例
推荐两种方式:
方式一:使用@InjectMocks自动注入依赖
替换手动创建Spy的方式,让Mockito自动将所有@Mock依赖注入到Service中:
@Mock CustomerProfile customerProfile; @Mock RestConsumerRequest<MortgPointsFulfillRequest> restConsumerRequest; @Mock CustomerProfileRepository customerProfileRepository; @Mock RestConnectorResponse<RestConsumerResponse<CustomerProfile>> restConnectorResponseC1; @InjectMocks CustomerProfileService customerProfileService; // Mockito自动完成依赖注入
方式二:手动初始化Spy(保留Spy场景)
如果需要使用Spy,在@BeforeEach方法中初始化,确保Mock对象已创建完成:
@Mock CustomerProfile customerProfile; @Mock RestConsumerRequest<MortgPointsFulfillRequest> restConsumerRequest; @Mock CustomerProfileRepository customerProfileRepository; @Mock RestConnectorResponse<RestConsumerResponse<CustomerProfile>> restConnectorResponseC1; CustomerProfileService customerProfileService; @BeforeEach void setUp() { customerProfileService = Mockito.spy(new CustomerProfileService(customerProfileRepository)); }
3. 可选:优化参数匹配逻辑
如果不需要严格匹配特定的restConsumerRequest对象,可以用any()替代,避免参数匹配失败:
doReturn(restConnectorResponseC1).when(customerProfileRepository).customerProfileLookup(any());
内容的提问来源于stack exchange,提问作者techie11
相关产品推荐
相关产品推荐

