4 Replies Latest reply on Apr 28, 2010 11:21 AM by nbelaevski

    Mock FacesContext in Spring Application Context?

    robertmarkbram

      Hi All,

       

      I am working on an app that is using Spring managed beans instead of Faces managed beans.

       

      I have a problem with a (Spring) @Component that has a @PostConstruct method which accesses session data via
      FacesContext.getCurrentInstance().getExternalConte xt().getSessionMap()

       

      In unit tests, *every* test that uses a Spring Context is failing (before @Before even) because this particular bean doesn't find the session data it is looking for in its @PostConstruct method (FacesContext.getCurrentInstance() is null).

       

      Is there a way to insert a MockFacesContext into my test application context? The test fails "before @Before even" so I can't even mock the data - the test fails before any code within it gets executed. I was looking at Mock Objects for Test Driven JSF Development:

      http://community.jboss.org/wiki/MockObjectsforTestDrivenJSFDevelopmentorgjbosstest-jsfjsf-mockproject

      but I couldn't see how to make this into a Spring component that loads in time.

       

      Thanks for any advice!

       

      Rob

       

        • 1. Re: Mock FacesContext in Spring Application Context?
          ilya_shaikovsky

          moving to RichFaces space from RichFaces development.

          • 2. Re: Mock FacesContext in Spring Application Context?
            nbelaevski

            Hi Robert,

             

            Can you please post test code?

            • 3. Re: Mock FacesContext in Spring Application Context?
              robertmarkbram

              Hi Nick,

               

              Here is an extract from my spring bean that has a @PostConstruct method that depends on FacesContext.

               

              @Component("headerBean")
              @Scope("request")
              public class HeaderBean {
                 @PostConstruct
                 public void init() {
                    String headerId = FacesContext.getCurrentInstance()
                          .getExternalContext().getSessionMap()
                          .get("headerID");
                    ....
                 }
              }
              This is a "view bean" (would be a managed bean if we were using pure JSF) and the intention that is that each time the view is loaded (each new request), the bean looks up headerId in the session. In the running application, this doesn't fail. In unit tests, it fails with the following exception:
              org.unitils.core.UnitilsException: Unable to create application context for locations [classpath:testApplicationContext.xml, classpath:data-access-config.xml]
              at org.unitils.spring.util.ApplicationContextManager.createInstanceForValues(ApplicationContextManager.java:121)
              at org.unitils.spring.util.ApplicationContextManager.createInstanceForValues(ApplicationContextManager.java:36)
                 ....
              Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'headerBean': Invocation of init method failed; nested exception is java.lang.NullPointerException
              at org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor.postProcessBeforeInitialization(InitDestroyAnnotationBeanPostProcessor.java:133)
              at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyBeanPostProcessorsBeforeInitialization(AbstractAutowireCapableBeanFactory.java:394)
              ... 29 more
              Caused by: java.lang.NullPointerException
              at au.com.tgg.roq.view.beans.HeaderBean.init(HeaderBean.java:135)
              ... 41 more

               

              With a bit further testing, I find that HeaderBean.init(HeaderBean.java:135) refers to FacesContext.getCurrentInstance() being null.

               

              1) The exact same error also occurs for any other unit test that uses a Spring Application Context, even if it never refers to HeaderBean. I wondered why is Spring instantiating all the beans at once and is this a Unitils issue instead? I asked that question on their forum (https://sourceforge.net/projects/unitils/forums/forum/570578/topic/3685714) and Tim answered "Unitils only creates a classpath xml application context, the rest is done by Spring."

               

              2) So, how can I inject a mock FacesContext into the Spring context? This error occurs before @Before in unit tests, so I can't avoid this issue by mocking the context in code.

               

              3) Alternatively, I can remove @PostConstruct from the init() method and call it in the JSP with: #{headerBean.init()}. This works too but feels hacky, plus I have to adjust unit tests to call init() all the time..

               

              4) Alternatively I can completely ignore the issue and put a null check in the init() method: a) the running app always has a Context at runtime so it's fine and b) mock a FacesContext in @Before and make sure init() is called "manually" again.

               

              Hope this detail is clear enough and not too much info.

               

              Thanks,

               

              Rob

               

              • 4. Re: Mock FacesContext in Spring Application Context?
                nbelaevski

                Ok, that's bean code, but can you please post test code so that I can see how Mock objects are being configured there and try to reproduce the problem locally?