4 Replies Latest reply on Sep 12, 2007 4:48 AM by Jan-Kees van Andel

    JSFUnit and HttpSession

    Jan-Kees van Andel Newbie

      Hi,

      I am trying JSFUnit and it is actually very nice. I have already tested some navigation rules and a bit of logic. However I think I have ran into something that is not yet supported (or I am doing something horribly wrong :-) ).

      My test application has a simple login screen, followed by a dummy landing page, which contains the name of the user that just logged in. It also contains a back button to go back to page 1.

      The problem is that session scoped variables (Managed Beans, SessionMap) are not stored for later use. This results in null values on later pages.

      For example, the username of the logged in user is shown on the first page after login, but when I try to retrieve it, another request later, it is null.

      The same is true for component tree variables, like the rendered attribute (rendered="#{sessionScopedBean.loggedIn}") I use in my test cases.

      Is this a fault of JSFUnit, Cactus, HttpUnit, or me?

      Below: A session test script and my cactus.properties. If necessary, I'll post my beans and JSP's...

      cactus.properties:

      cactus.contextURL=http://localhost:8080/jsfunittest
      cactus.servletRedirectorName=JSFUnitRedirector
      


      Test script:
      public class SessionTest extends ServletTestCase{
      
       private ClientFacade client;
      
       private ServerFacade server;
      
       protected void setUp() throws Exception {
       super.setUp();
       client = new ClientFacade("/login.faces");
       server = new ServerFacade();
       }
      
       public void testInitialPage() throws IOException, SAXException {
       FacesContext facesContext = FacesContextBridge.getCurrentInstance();
       assertEquals("/login.jsp", server.getCurrentViewId());
       server.getFacesContext().getExternalContext().getSessionMap().put("var", "value");
       }
      
       public void testNavigation() throws IOException, SAXException {
       WebForm form = client.getForm();
       form.setParameter("form:username", "user");
       form.setParameter("form:password", "pass");
       client.submit();
      
       assertEquals("/loggedin.jsp", server.getCurrentViewId());
      
       String var = (String)server.getFacesContext().getExternalContext().getSessionMap().get("var");
       System.out.println(var);
       assertEquals("value", var);
       }
      }
      



        • 1. Re: JSFUnit and HttpSession
          Stan Silvert Master

          Hi,

          Thanks for your interest in JSFUnit. And thank you for the kind words.

          In a JSFUnit test, when you call FacesContext.getExternalContext() you will get an instance of JSFUnitExternalContext. The reason there is a special implementation of ExternalContext is because the request is actually over and some of the environment has been torn down by the servlet container. Just before the request ends, the JSFUnitExternalContext caches as much context information as it can and then provides most of it as read-only. Thus, the write-through properties of the session map and the application map are not maintained.

          However, you can still access the "live" HttpSession from the JSFUnitExternalContext and use it. So your test would work if you rewrote it like this:

          public class SessionTest extends ServletTestCase{
          
           private ClientFacade client;
          
           private ServerFacade server;
          
           protected void setUp() throws Exception {
           super.setUp();
           client = new ClientFacade("/login.faces");
           server = new ServerFacade(client);
           }
          
           public void testInitialPage() throws IOException, SAXException {
           assertEquals("/login.jsp", server.getCurrentViewId());
           HttpSession session = (HttpSession)server.getFacesContext().getExternalContext().getSession(true);
           session.setAttribute("var", "value");
           }
          
           public void testNavigation() throws IOException, SAXException {
          
           client.setParameter("username", "user");
           client.setParameter("password", "pass");
           client.submit();
          
           assertEquals("/loggedin.jsp", server.getCurrentViewId());
          
           HttpSession session = (HttpSession)server.getFacesContext().getExternalContext().getSession(true);
           assertEquals("value", session.getAttribute("var");
           }
          }


          A few notes:
          * I used the latest API for the Facades.
          * ServerFacade no longer has a no-arg constructor.
          * You don't need to get the WebForm. Params can be set from the ClientFacade.
          * Your code requires that testInitialPage() is called before testNavigation(). I'm not sure if JUnit guarantees this ordering of tests.

          Lastly, thanks for pointing this out. I'm going to change the JSFUnitExternalContext so Maps that lose their write-through capability will throw an exception if you try to modify them. Then it will be obvious what is happening and you won't get the silent failure that you encountered.
          See http://jira.jboss.com/jira/browse/JSFUNIT-20

          Regards,

          Stan
          http://www.jsfunit.org

          • 2. Re: JSFUnit and HttpSession
            Jan-Kees van Andel Newbie

            Thanks for the quick reply. I'll try your solution later today.

            However, the test I posted was only a sample test, created just for this forum. It served the purpose of indicating that the session was the problem. My real problem, however, is that my session scoped Managed Beans lose their values.

            For example, in my real test, I created a login page and a "login success" page. All request scoped variables are kept, just as you would expect, but the session scoped bean, which holds a username, is removed.

            What kind of solution would you suggest for this problem? After all, I don't use getSession when I access my managed bean properties. I use getManagedBeanValue. Or can I force the session to restore by calling getSession(true) before calling getManagedBeanValue?

            • 3. Re: JSFUnit and HttpSession
              Stan Silvert Master

              I think I see your problem now. The ClientFacade simulates a single user session. So every time a new ClientFacade is created, the HttpSession will be cleared. If you are treating two test methods as one session with the ClientFacade created during setUp() then you will see the problem.

              Stan

              • 4. Re: JSFUnit and HttpSession
                Jan-Kees van Andel Newbie

                LOL, I'm so stupid. Didn't notice the setUp is called before every test method.

                And about the order of JUnit test methods. That is indeed not guaranteed.