使用when/thenReturn后方法仍返回null的PowerMock排查
测试Handler.handleRequest时返回null的问题排查
我在测试Handler类的handleRequest方法时,已使用PowerMock创建Client、DocumentType等Mock实例,通过whenNew模拟Client实例化,并用when/thenReturn设置方法返回值,但调用handleRequest后结果仍为null,无法通过assertNotNull断言。
测试代码
@Mock Client clientMock; @Mock DocumentType documentMock; @Mock LambdaLogger logger; @InjectMocks Handler handler; // Handler类已标注@ExtendWith(MockitoExtension.class)和@RunWith(PowerMockRunner.class) @Test public void handleRequest() { Handler handler = new Handler(); EventRequest request = buildEventRequest(); String property1 = "abcd"; String property2 = "1234"; PowerMockito.whenNew(Client.class).withAnyArguments().thenReturn(clientMock); PowerMockito.when(clientMock.getToken(logger, "sampleId")).thenReturn("sampleToken"); PowerMockito.when(clientMock.getDocument(property1, property2, logger)).thenReturn(document); Object result = handler.handleRequest(request, context); assertNotNull(result); }
被测试Handler类代码
public class Handler{ public Object handleRequest(Object object, Context context) { DocumentType document = getTheDocument(object.getProperties()); //调用类内私有方法 if (document != null) { document.setNewProperties(abc); } return document; } private DocumentType getTheDocument(String property1, String property2, LambdaLogger logger) { Client client = new Client(); //需模拟此Client实例以获取document DocumentType document = new DocumentType(); document = client.getDocument(property1, property2); return document; } }
Client类结构
public class Client{ public Object getDocument(String property1, String property2, LambdaLogger logger) { String token = getToken(logger, property1); // 发送POST请求获取CloseableHttpResponse,调用静态方法获取document Document document = AnotherClass.getDocument(closeableHttpResponse); // 从JAXBContext创建Unmarshaller,处理输入流 document = (DocumentType) unmarshaller.unmarshall(inputstream); return document; } public String getToken(LambdaLogger logger, String id) { // 返回AWSSecretsManager密钥 } }
疑问点
- 是否需要模拟getToken这类内部方法?
- 为什么clientMock.getDocument的stub不生效?
- 是否需要通过反射调用私有方法getTheDocument来测试?
已知unmarshaller.unmarshall(inputstream)是返回null的环节,且我无法修改原代码,仅能编写测试用例,请求排查建议。
排查建议
解决clientMock.getDocument stub不生效的核心问题
- 测试中同时使用
@InjectMocks和手动new Handler(),会产生两个独立的Handler实例,PowerMock的mock配置仅对@InjectMocks注入的实例生效,需删除手动new的代码,直接使用注入的handler实例。 - 检查方法签名匹配:Handler私有方法中调用的是
client.getDocument(property1, property2)(2个参数),但测试中stub的是clientMock.getDocument(property1, property2, logger)(3个参数),参数数量不匹配导致stub未触发,需调整stub的方法签名与实际调用完全一致。 - 测试类需添加
@PrepareForTest({Handler.class, Client.class})注解,PowerMock需要提前准备要mock的类(尤其是涉及whenNew和私有方法的类)。
- 测试中同时使用
关于是否需要模拟getToken
- 不需要。因为已经mock了Client实例,只要正确stub
getDocument的返回值,Client内部的getToken调用不会执行真实逻辑,直接返回你预设的documentMock即可。
- 不需要。因为已经mock了Client实例,只要正确stub
关于是否需要反射调用私有方法
- 优先测试public方法
handleRequest,这更符合黑盒测试的业务场景,能完整验证整个流程。只有当public方法逻辑过于复杂,需要单独验证私有方法的局部逻辑时,才考虑反射调用。当前问题是mock配置错误,优先解决mock问题即可。
- 优先测试public方法
针对unmarshaller返回null的问题
- 由于无法修改原代码,必须确保Client.getDocument的mock返回正确的documentMock。除了修正上述stub配置问题,还要确认
whenNew(Client.class)的配置正确作用到Handler的私有方法中,确保Handler内部new出来的Client是你mock的clientMock实例。
- 由于无法修改原代码,必须确保Client.getDocument的mock返回正确的documentMock。除了修正上述stub配置问题,还要确认
内容的提问来源于stack exchange,提问作者Sparrow
相关产品推荐
相关产品推荐

