how to mock a servletContext instead of Servlet or HttpServletRequest? - java

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?

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);
}

Related

Different ways to get Servlet Context

Could anybody explain me what is the difference between this ways of getting the ServletContext of an HttpServlet?
doGet( HttpServletRequest request, ... ){
getServletConfig( ).getServletContext( );
request.getSession( ).getServletContext( );
getServletContext( );
}
Is there any difference in performance or in the context itself? If so, which is the best way? Are there any other way of retrieving the context?
There's one more.
request.getServletContext();
There's technically no difference in performance, only the request.getSession() will implicitly create the HTTP session object if not created yet. So if this is not done yet, then grabbing the servlet context via the session may take a few nanoseconds longer if the session isn't created yet.
There's also no difference in the returned context. Those methods are all just for convenience and which method to obtain the context depends on the context ;) you're currently sitting in.
If you're sitting in a method invoked by servlet's service() (such as doGet(), doPost(), etc), then just use the inherited getServletContext() method. Other ways only unnecessarily add more characters to the source code.
#Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) {
ServletContext context = getServletContext();
// ...
}
If you're sitting in servlet's init(ServletConfig) method, then the inherited getServletContext() isn't available yet as long as you haven't called super.init(config). You'd need to grab it from ServletConfig.
#Override
public void init(ServletConfig config) {
ServletContext context = config.getServletContext();
// ...
}
But much better is to override init() instead. In a decent servlet you usually never need to override init(ServletConfig).
#Override
public void init() {
ServletContext context = getServletContext();
// ...
}
If you're not sitting in a servlet but in e.g. a filter which lacks the inherited getServletContext() method and you only have ServletRequest at hands, then you could grab it from there.
#Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) {
ServletContext context = request.getServletContext();
// ...
}
Note that this is new since Servlet 3.0. Previously, you'd have to grab it from the session.
#Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) {
ServletContext context = request.getSession().getServletContext();
// ...
}
This is however not nice if you worry about unnecessary session creation. Hence the introduction of ServletRequest#getServletContext() — although you could also simply extract it from FilterConfig (hey, there's yet another way!).
private FilterConfig config;
#Override
public void init(FilterConfig config) {
this.config = config;
}
#Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) {
ServletContext context = config.getServletContext();
// ...
}
And then there are HTTP session listeners where you could listen on a.o. session destroy. There's no other way to obtain the servlet context than via HttpSession#getServletContext().
#Override
public void sessionDestroyed(HttpSessionEvent event) {
ServletContext context = event.getSession().getServletContext();
// ...
}
Here you don't need to worry about unnecessary session creation because it's at that point already created for long beforehand. Do note that there's no ServletRequest anywhere as there's not necessarily means of an active HTTP request during server side session timeout.
As last, there's also ServletContext#getContext() which returns the ServletContext of a different web application deployed to same server (this works only if the server is configured to enable cross context access on the target webapp).
ServletContext otherContext = context.getContext("/otherContextPath");
But this already requires the current ServletContext to start with, for which you should by now already know which way to use to obtain it.

Get current request in Custom Spring Scope

i write a custom spring scope base on FacesContext Logique,
public class DynamicScope implements Scope{
#Override
public Object get(String name, ObjectFactory<?> objectFactory) {
AbsErpFolder erpFolder = null;
if (FacesContext.getCurrentInstance()!=null)
erpFolder = (AbsErpFolder)FacesUtils.getExternalContext().
getRequestMap().get( ErpFolderKey );
............
}
Now i need to instanciate a bean in FileServlet Filter using
WebApplicationContext wsc = WebApplicationContextUtils.getWebApplicationContext(config.getServletContext());
IGenericService erpFileService = (IGenericService) wsc.getBean("erpFileService");
The problem is during the execution my ServletFile the current FacesContext is null (the dynamic scope can't work ) so how to get the current request ?
ThreadLocal should do the trick
( Defined in my first Filter )
public static ThreadLocal servletRequestHolder = new ThreadLocal();
public static HttpServletRequest getCurrentRequest(){
return (HttpServletRequest) servletRequestHolder.get();
}
#Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
servletRequestHolder.set( request );
...........
}

Mocked object to return actual data

//MyServlet.java
public class MyServlet extends HttpServlet {
public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, Exception {
int sum = Integer.parseInt(request.getParameter("a")) + Integer.parseInt(request.getParameter("b"));
request.setAttribute("sum",sum);
RequestDispatcher dispatcher=request.getRequestDispatcher("/ShowSum.jsp");
dispatcher.forward(request,response);
}
}
//TestServelt.java
public class TestServelt {
#Test
public void testSum() throws Exception {
HttpServletRequest request = mock(HttpServletRequest.class);
HttpServletResponse response = mock(HttpServletResponse.class);
RequestDispatcher dispatcher = mock(RequestDispatcher.class);
when(request.getParameter(a)).thenReturn(10);
when(request.getParameter(b).thenReturn(20);
when(request.getRequestDispatcher(anyString())).thenReturn(dispatcher);
MyServlet testServlet = new MyServlet ();
testServlet.doPost(request, response);
int sum = (int)request.getAttribute("sum"); // here it's will return NULL.
}
}
I am trying to write somewhat similar Test case for a servlet
as u can see , that sum variable can't be mocked cuz that will defeat the purpose , i want it to return what got calculated after the servlet call. can anyone help or give a different approach.
You can't use mock objects in this case; mock objects are just thin API layers, they have no functionality or intelligence.
Use a framework with simulates the Servlet API like mockrunner or the Spring Web testing framework.

Static or nonstatic action in mvc?

i want to ask you about mvc. How it works. So, this is simple example(I don't use any frameworks)
in Controller(Servlet):
protected void doGet(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
processRequest(request, response);
}
protected void doPost(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
processRequest(request, response);
}
private void processRequest(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
String page = null;
AbstractCommand action;
action = ActionFactory.getAction(request);// get command from factory
page = action.execute(request, response);
RequestDispatcher dispatcher = getServletContext()
.getRequestDispatcher(page);
dispatcher.forward(request, response);
}
for action we create a common interface(Strategy pattern):
public interface AbstractAction {
public String execute(HttpServletRequest request, HttpServletResponse response);
}
Simple Action(Example):
public class HelloAction implements AbstractAction {
#Override
public String execute(HttpServletRequest request,
HttpServletResponse response) {
//....(some actions to modify request)
String page = "/main.jsp";
return page;
}
}
And now, our factory:
public class ActionFactory {
private enum Actions{
HELLO;
}
public static AbstractAction getAction(HttpServletRequest request){
String action = request.getParameter("action");//take parameter from jsp
Actions actionEnum = Actions.valueOf(action.toUpperCase());
switch (actionEnum) {
case HELLO:
return new HelloAction();
}
}
}
We came to the place where I am in confused. Servlet is initialized only once, and only one for all requests. Just forwards requests to the actions where we modify request or response. But, we create NEW instance of the class for every request. Here can occur memory overflow!? Or not?
Can we make these actions static(static method, one for all request)? If two requests come at the same time what will happen to them?
What do you think about this, please share your experience.
P.S. sorry for bad english.
How about Singleton pattern to get the instance of the Action class ?
Just add some abstact getInstance() method in AbstractAction.
Make every implementation provide its own instance.
In every implementation class, use Singleton pattern so that only one instance exists.
Make sure no action class stores any data related to a specific request.
As i understood the jsp, the whole thing is stateless, if u access the servlet by http request, the servlet will be created in a new instance.
After leaving the servlet by .forward(), it will be released by garbage collection.
2,3,...,n requests = 2,3,...,n servlets.
by forwarding to a jsp, the only way to access the servlet from jsp is a new http request = new servlet. ( will move to the doPost method)

How to use the "application" object in a Servlet?

If we are coding a JSP file, we just need to use the embedded "application" object. But how to use it in a Servlet?
The application object in JSP is called the ServletContext object in a servlet. This is available by the inherited GenericServlet#getServletContext() method. You can call this anywhere in your servlet except of the init(ServletConfig) method.
public class YourServlet extends HttpServlet {
#Override
public void init() throws ServletException {
ServletContext ctx = getServletContext();
// ...
}
#Override
public void doGet(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {
ServletContext ctx = getServletContext();
// ...
}
#Override
public void doPost(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {
ServletContext ctx = getServletContext();
// ...
}
}
See also Different ways to get Servlet Context.
The application object references javax.servlet.ServletContext and you should be able to reference that in your servlets.
To reference the ServletContext you will need to do the following:
// Get the ServletContext
ServletConfig config = getServletConfig();
ServletContext sc = config.getServletContext();
From then on you would use the sc object in the same way you would use the application object in your JSPs.
Try this:
ServletContext application = getServletConfig().getServletContext();
In a Java web application you often have the request object. So you can get the "application" object like this:
request.getServletContext().getServerInfo()

Categories