0

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);
Ovi Faur
  • 518
  • 3
  • 19
  • Very curious. I'm inclined to suspect that the example you've presented is not representative of the real code in which the problem first arose -- that either you're not using the same key to retrieve the value that you used to set it, or maybe that you're reading back `null` because that's the value you're actually setting. Can you really produce the behavior you describe via the exact code you've presented? – John Bollinger Mar 20 '17 at 13:37
  • Yes you are right. This is just a sample code which produces the same result. And yes, running the junit test for this class produces the above output. That is why I thought I'm missing something. I am using the same key to retrieve it, it's a constant. – Ovi Faur Mar 20 '17 at 13:39
  • The fact that this behavior was observed during unit testing changes everything. In that case, it's highly relevant exactly what is being tested -- I suppose probably your listener's `contextInitialized()` method -- *and how the test fixture is set up to mock the execution environment*. It is entirely plausible that the behavior you observe arises because the test fixture does not adequately mock a servlet container. For example, maybe its `ServletContextEvent.getContext()` implementation returns a new object on every invocation. – John Bollinger Mar 20 '17 at 13:46
  • See updated question. – Ovi Faur Mar 20 '17 at 13:50

1 Answers1

2

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.

John Bollinger
  • 160,171
  • 8
  • 81
  • 157
  • This was the generic problem, my actual solution to this was to mock it like: when(servletContext.getAttribute(anyString())) .thenReturn("my value"); – Ovi Faur Mar 21 '17 at 07:19