如何在Mockito中Mock Servlet Context?Servlet测试空指针问题求助
Hey there, let's tackle that NullPointerException you're facing when trying to mock ServletContext for your Servlet test. The root of the problem is that your Servlet instance doesn't have a reference to your mocked ServletContext—here's how to fix it:
Why the NPE Happens
When you create a Servlet instance with new httpt_vb_getTableNames(), its internal ServletConfig is null. The getServletContext() method in Servlet actually delegates to getServletConfig().getServletContext(), so without a configured ServletConfig, this returns null, causing your NPE.
Solution: Mock ServletConfig and Initialize the Servlet
You need to mock a ServletConfig, link it to your mocked ServletContext, then initialize the Servlet with this config. Here's how to adjust your test code:
Updated Test Code
public class http_vb_getTableNamesServletTest { @Mock HttpServletRequest request; @Mock HttpServletResponse response; @Mock HttpSession session; @Mock RequestDispatcher rd; @Mock ServletOutputStream servletOut; @Mock ServletContext sc; @Mock ServletConfig servletConfig; // Add this mock @Mock FilterConfig filterConfig; public final static String Seperator = new Character((char)1).toString(); public final static String ContentDelimeter = new Character((char)2).toString(); @Before public void setUp() throws Exception { MockitoAnnotations.initMocks(this); // Link ServletConfig to ServletContext when(servletConfig.getServletContext()).thenReturn(sc); } @Test public void test() throws Exception { DataSet ds=new DataSet(); String buffer=ds.getUserId()+Seperator+ds.getUsername(); ByteArrayOutputStream bos = new ByteArrayOutputStream (); ZipOutputStream out = new ZipOutputStream(bos); out.putNextEntry(new ZipEntry("request.txt")); out.write(buffer.getBytes("UTF-8")); out.closeEntry(); out.close(); bos.close(); String b64String = Base64.encodeBase64String(bos.toByteArray()); Reader inputString = new StringReader(b64String); BufferedReader reqbuffer = new BufferedReader(inputString); httpt_vb_getTableNames servlet=new httpt_vb_getTableNames(); // Initialize the Servlet with the mocked config servlet.init(servletConfig); when(request.getReader()).thenReturn(reqbuffer); when(response.getOutputStream()).thenReturn(servletOut); when(sc.getRequestDispatcher("/jsp/admin/chooseNeighborhood.jsp")).thenReturn(rd); when(sc.getRequestDispatcher("/jsp/admin/joinNeighborhood.jsp")).thenReturn(rd); servlet.service(request, response); ArgumentCaptor<String> bufferCaptor = ArgumentCaptor.forClass(String.class); verify(servletOut).print(bufferCaptor.capture()); String responseBody = bufferCaptor.getValue(); ZipInputStream zipIn = new ZipInputStream(new ByteArrayInputStream(Base64.decodeBase64(responseBody.toString().getBytes()))); zipIn.getNextEntry(); StringBuffer sb = new StringBuffer(); ByteArrayOutputStream out1 = new ByteArrayOutputStream(); IOUtils.copy(zipIn, out1); sb = new StringBuffer(); sb.append(out1.toString("UTF-8")); String[] res=sb.toString().split(Seperator); AssertJUnit.assertEquals("Success",res[0]); } }
Key Changes Explained
- Added a
@Mock ServletConfig servletConfigfield to mock the Servlet's configuration. - In
setUp(), we tell Mockito that whenservletConfig.getServletContext()is called, it should return our mockedsc. - Before calling
servlet.service(), we invokeservlet.init(servletConfig)—this tells the Servlet to use our mocked configuration, sogetServletContext()will now return your mockedServletContextinstead ofnull.
Alternative: Use @InjectMocks (Optional)
If you prefer, you can use @InjectMocks to let Mockito inject the mocked ServletContext directly into the Servlet via reflection. However, the ServletConfig approach is more aligned with how Servlets work natively, so it's generally the more reliable choice.
内容的提问来源于stack exchange,提问作者Jaydeep Bobade

