Search code examples
javaweb.xmlservletcontextlistener

ServletContextListener attribute set in event is null


I have a ServletContextListener like the one below

public class MyServletContextListener implements ServletContextListener {

@Override
public void contextInitialized(ServletContextEvent servletContextEvent) {
    System.out.println("Start");
    servletContextEvent.getServletContext().setAttribute("id1", "this is my value");
    System.out.println("Current value is" + servletContextEvent.getServletContext().getAttribute("id1"));
    System.out.println("End");
}

This will print:

Start
Current value is null
End

Yes, the listener is defined in the web.xml:

<listener>
    <listener-class>package.path.MyServletContextListener</listener-class>
</listener>

What am I missing?

LE: I am obtaining this in my unit tests(using junit and mockito). In my TestClass I have a @BeforeClass method in which I do the following:

ServletRunner sr = new ServletRunner(new File("src/test/resources/WEB-INF/web.xml"));
ServletUnitClient sc = sr.newClient();

listener = new MyServletContextListener ();

    event = mock(ServletContextEvent.class);
    servletContext = mock(ServletContext.class);

    when(event.getServletContext()).thenReturn(servletContext);

    listener.contextInitialized(event);

Solution

  • The problem appears to be in your ServletContext mock. You create it via Mockito.mock(ServletContext.class), and Mockito is clever enough to provide an object that implements all the ServletContext methods, but how do you suppose it would know what behavior to implement?

    By itself, it can't, not with just the interface class to go on. All Mockito can do is provide stubs with the correct signatures. You've done nothing (in what you present) to provide for the mock's setAttribute() method to actually record the attribute that was set, or for its getAttribute() method to look up and return that object. Mockito can support that, it appears, but you'll need to tell it what to do.

    Note also that if the point is to verify that the contextInitialized() method sets an attribute, then the best way to check is by instrumentating the ServletContext mock, not by observing the listener's output to System.out. Relying on the output brings that, too, into the scope of the test, so now you're jointly testing two distinct functionalities.