Sling Servlet单元测试返回null 无法正确调用方法排查
问题定位
你的测试跑失败是三个低级错误叠出来的:
- 校验对象取错了:你Servlet里明明是调用
response.setContentType(APPLICATION_JSON)往响应对象写Content-Type头,测试里居然去读req.getContentType()——请求的Content-Type是调用方发请求带的头,你测试里从来没给请求设过这个值,拿到的当然是null。 - 测试场景根本没走到设响应头的逻辑分支:看你Servlet代码,只有参数解析正常、业务方法调用成功的try块里才会设置响应Content-Type。你现在测试里啥请求参数都没传,
Double.parseDouble(request.getParameter("amount"))拿不到值直接抛NumberFormatException,直接进catch块了,catch块里根本没写设Content-Type的逻辑,就算你改对读response的头,这个场景下也拿不到application/json。 - 断言方法参数顺序写反了:JUnit的
assertEquals要求第一个参数传预期值,第二个传代码实际产出的值,你把实际拿到的null放第一个参数位、预期的"application/json"放第二个,才会出现报错里Expected是null、Actual是字符串的反常输出。
另外你测试初始化逻辑写得很乱:同时打了@Mock/@InjectMocks注解,又在setup方法里手动new Servlet、手动从context拿新的request/response对象赋值,会导致注入的依赖和测试里实际用的对象不是同一个,属于埋坑的写法,这次报错不是它直接导致的,但迟早出问题。
修复步骤
1. 补全Servlet异常分支的响应头设置
不管请求处理成功还是失败,都应该给响应设正确的Content-Type,不然接口报错时返回的头不符合预期:
catch (NullPointerException | NumberFormatException exception) { LOG.error("{} : Exception when parsing request parameters : ", LOG_STRING, exception); responseText = "Error when parsing request parameters"; response.setContentType(APPLICATION_JSON); // 异常分支也加上头设置 }
2. 重写测试逻辑
- 删掉冲突的Mock注解,统一用Sling Context构造测试对象
- 测试正常场景时,先给请求塞必填的三个参数,同时mock掉业务依赖方法的返回值,确保逻辑能走到设响应头的分支
- 断言时读响应对象的Content-Type,调整断言参数顺序
修正后的正常场景测试代码:
private MockSlingHttpServletRequest req; private MockSlingHttpServletResponse res; private CurrencyExchangeServlet underTest; // 如果你用的是Sling/AEM测试的@Rule SlingContext context,保留即可 @Before public void setup() { underTest = new CurrencyExchangeServlet(); // 手动注入Servlet依赖的currencyRatesCalculation mock对象 underTest.currencyRatesCalculation = Mockito.mock(CurrencyRatesCalculation.class); req = context.request(); res = context.response(); } @Test public void doGet_shouldReturnJsonHeaderWhenRequestSuccess() throws IOException { // 构造合法请求参数 req.setParameter("base", "USD"); req.setParameter("convertTo", "CNY"); req.setParameter("amount", "100"); // mock业务方法返回,避免空指针 Mockito.when(underTest.currencyRatesCalculation.getConvertedAmount(anyString(), anyString(), anyDouble())) .thenReturn("{\"convertedAmount\":720.0}"); underTest.doGet(req, res); // 第一个参数传预期值,第二个传实际值,读取response的Content-Type assertEquals("application/json", res.getContentType()); }
3. 补充异常场景测试
单独写用例验证参数缺失的异常场景,确保异常分支逻辑符合预期:
@Test public void doGet_shouldReturnErrorWhenRequestParamInvalid() throws IOException { // 不传任何参数,触发异常分支 underTest.doGet(req, res); assertEquals("application/json", res.getContentType()); assertEquals("Error when parsing request parameters", res.getOutputAsString()); }
内容的提问来源于stack exchange,提问作者Stefan
相关产品推荐
相关产品推荐

