I have an independent project for writing test cases; the problem is I can't mock HttpServletRequest
, simply because in my servlet there are calls like getServletContext()
as test cases are running from the outside servlet container. It will always return an error saying "no context found". This is just one dependency with the servlet container; there can be hundreds. For example, initialContext.lookup()
also depends on a container.
How can I use Mockito to write a test case in this scenario? Please don't ask for an error message; it's more of a logical problem than technical.
Looking on the internet for tutorials makes me wonder if I am doing something seriously wrong. No one seems to have encountered this problem before... How can you mock HttpServletRequest
without ever having getServletContext()
called in the servlet? I mean seriously, how rare can it be?
public class MockHttpServletRequest extends Object implements HttpServletRequest. Mock implementation of the HttpServletRequest interface. The default, preferred Locale for the server mocked by this request is Locale. ENGLISH . This value can be changed via addPreferredLocale(java.
Since the ServletContext object is available to all the servlets of the Web application, other servlets can retrieve the attribute from the ServletContext object by using the getAttribute() method.
You have a servlet implementation that uses the ServletContext
, e.g.
public class SomeServlet extends HttpServlet{
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
ServletContext servletContext = getServletContext();
Object attribute = servletContext.getAttribute("test");
System.out.println(attribute.toString());
}
}
in this case you have 2 options to test the doGet
method
Use powermock's partitial mocking to only mock the getServletContext
method.
@RunWith(PowerMockRunner.class)
public class SomeServletTest {
@Test
public void onGet() throws ServletException, IOException{
SomeServlet someServlet = PowerMock.createPartialMock(SomeServlet.class, "getServletContext");
ServletContext servletContext = PowerMock.createNiceMock(ServletContext.class);
HttpServletRequest httpServletRequest = PowerMock.createNiceMock(HttpServletRequest.class);
HttpServletResponse httpServletResponse = PowerMock.createNiceMock(HttpServletResponse.class);
someServlet.getServletContext();
PowerMock.expectLastCall().andReturn(servletContext);
servletContext.getAttribute("test");
PowerMock.expectLastCall().andReturn("hello");
PowerMock.replay(someServlet, servletContext, httpServletRequest, httpServletResponse);
someServlet.doGet(httpServletRequest, httpServletResponse);
}
}
or a simpler way is to just override the getServletContext
method. In this case you don't need powermock. You can just do it using easymock. e.g.
public class SomeServletTest {
@Test
public void onGet() throws ServletException, IOException{
HttpServletRequest httpServletRequest = EasyMock.createNiceMock(HttpServletRequest.class);
HttpServletResponse httpServletResponse = EasyMock.createNiceMock(HttpServletResponse.class);
final ServletContext servletContext = EasyMock.createNiceMock(ServletContext.class);
SomeServlet someServlet = new SomeServlet(){
public ServletContext getServletContext() {
return servletContext; // return the mock
}
};
EasyMock.expect(servletContext.getAttribute("test")).andReturn("hello");
EasyMock.replay(servletContext, httpServletRequest, httpServletResponse);
someServlet.doGet(httpServletRequest, httpServletResponse);
}
}
there can be 100's. like initialContext.lookup() also dependent on container.
In this case you can either create an InitialContext
mock and use this.
If your code creates a new InitialContext
, e.g.
public void someMethod(){
InitialContext context = new InitialContext();
context.lookup(....);
}
you can simply extract the InitialContext
instantiation to a protected method that you can override in your tests like I showed above with the ServletContext
public void someMethod(){
InitialContext context = createInitialContext();
context.lookup(....);
}
protected InitialContext createInitialContext(){
return new InitialContext(); // can be overridden by a subclass
// and therefore by tests as well to
// return a mock
}
If you don't want or you can't modify the code in this way, then you can use Powermock
to intercept the constructor.
EDIT
Can you post your Mockito code? It would be a pleasure, since the methods are named differently.
@Test
public void onGet() throws ServletException, IOException {
HttpServletRequest httpServletRequest = Mockito.mock(HttpServletRequest.class);
HttpServletResponse httpServletResponse = Mockito.mock(HttpServletResponse.class);
final ServletContext servletContext = Mockito.mock(ServletContext.class);
SomeServlet someServlet = new SomeServlet(){
public ServletContext getServletContext() {
return servletContext; // return the mock
}
};
Mockito.doReturn("hello").when(servletContext).getAttribute("test");
someServlet.doGet(httpServletRequest, httpServletResponse);
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With