Announcement Announcement Module
Collapse
No announcement yet.
Accessing WebApplicationContext from TestContext Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Accessing WebApplicationContext from TestContext

    Hi

    I am using AbstractTransactionalJUnit4SpringContextTests to do some MVC integration testing and I need to access the WebApplicationContext.

    It appears that TestContext with contextConfiguration makes a GenericApplicationContext available but I can't see how to access or create a WebApplicationContext.

    This is currently a showstopper for me - any assistance greatly appreciated.

    Thanks ........Geoff

  • #2
    8.3.7.5. TestContext support classes -> 8.3.7.5.2. JUnit 4.4 support classes:
    AbstractTransactionalJUnit4SpringContextTests:

    Abstract transactional extension of AbstractJUnit4SpringContextTests that also adds some convenience functionality for JDBC access. Expects a javax.sql.DataSource bean and a PlatformTransactionManager bean to be defined in the ApplicationContext.

    When you extend AbstractTransactionalJUnit4SpringContextTests you will have access to the following protected instance variables:

    *applicationContext: inherited from the AbstractJUnit4SpringContextTests superclass. Use this to perform explicit bean lookups or to test the state of the context as a whole.
    ...

    Comment


    • #3
      Denis, this *applicationContext is the GenericApplicationContext - there doesn't appear to be away of getting the WebAppliactionContext from it.

      Cheers .......Geoff

      Comment


      • #4
        Do you need WebApplicationContext specific methods available in your tests or are the context failing due to mvc related stuff?

        In case of failure, split you context in multiple files and leave out the mvc related stuff in one of them and use this one for testing.

        Maybe this is not sufficient for what you are trying to do though...

        G

        Comment


        • #5
          Hi guys,

          It is correct that the Spring TestContext Framework does not support creation of a WebApplicationContext out-of-the-box; however, there are certainly hooks in place to achieve this goal with custom code. For example, you might find Dhruba Bandopadhyay's recent blog on Using MockServletContext and ContextLoader with Spring 2.5 TestContext framework useful.

          Regards,

          Sam

          Comment


          • #6
            Hi Goran / Sam

            Many thanks for your replies.

            Goran : I'm seeing both, a XmlViewResolver fails context and I'm trying to recover command object property validation errors using RequestContext which requires WebApplicationContext.

            Sam : I'm still pretty new to the TestContext - I've followed Dhruba's suggestions and this does provide a XmlWebApplicationContext but Dependancy Injection no longer works (which it does using the default loader) even with @TestExecutionListeners({DependencyInjectionTestEx ecutionListener.class})

            Any further pointers, much appreciated.

            Thanks ............Geoff

            Comment


            • #7
              Hi Geoff,

              Originally posted by GeoffM View Post
              Sam : I'm still pretty new to the TestContext - I've followed Dhruba's suggestions and this does provide a XmlWebApplicationContext but Dependancy Injection no longer works (which it does using the default loader) even with @TestExecutionListeners({DependencyInjectionTestEx ecutionListener.class})
              I've not actually tried to use Dhruba's code; however, try moving the call to
              context.refresh() below the call to AnnotationConfigUtils.registerAnnotationConfigProc essors((BeanDefinitionRegistry) context.getBeanFactory()) and see if that makes a difference.

              If that doesn't work, consider posting a comment to Dhruba's blog.

              Regards,

              Sam

              Comment


              • #8
                Hi Sam

                Moving refresh() triggered - Caused by: java.lang.IllegalStateException: BeanFactory not initialized or already closed - call 'refresh' before accessing beans via the ApplicationContext. Adding a second refresh() made no difference.

                Am I trying to do something unusual (needing access to WebApplicationContext ) for MVC integration testing ? I would have thought creating / accessing a similiar applicationContext ( contextLoader : DispatchServlet ) within a testContext would be key.

                Thanks for your reponses - I'll see if Dhruba has a solution.

                Geoff
                Last edited by GeoffM; Oct 27th, 2008, 12:23 PM. Reason: typo

                Comment


                • #9
                  Hi Geoff,

                  Originally posted by GeoffM View Post
                  Moving refresh() triggered - Caused by: java.lang.IllegalStateException: BeanFactory not initialized or already closed - call 'refresh' before accessing beans via the ApplicationContext. Adding a second refresh() made no difference.
                  OK, that might be due to differences in the XmlWebApplicationContext and GenericApplicationContext class hierarchies. Like I said, I haven't actually tried to use Dhruba's code.

                  Originally posted by GeoffM View Post
                  Am I trying to do something unusual (needing access to WebApplicationContext ) for MVC integration testing ?
                  I don't think it's that unusual: it's just something we didn't add to Spring 2.5.x out-of-the-box, since people typically test their web components (e.g., controllers, servlets, filters, etc.) outside of the ApplicationContext in unit tests with mock objects for the ServletContext, HttpServletRequest, etc. However, if you'd like to see explicit support for loading a WebApplicationContext with the Spring TestContext Framework, you might consider creating a JIRA issue to suggest this for Spring 3.0.

                  Regards,

                  Sam

                  Comment


                  • #10
                    Hi Sam

                    I've followed your advice and raised SPR-5243. Hopefully a few others will add their support and vote for it's inclusion.

                    Thanks for your assistance ............Geoff

                    Comment


                    • #11
                      How about this?
                      in your test:
                      Code:
                      @RunWith(.....
                      @ContextConfiguration(loader=MyContextLoader.class, locations={"classpath:my-application-context.xml"})
                      public class DelegatingTagLibProxyTest {
                          // use 
                          // WebApplicationContextUtils.getRequiredWebApplicationContext(MyContextLoader.SERVLET_CONTEXT)
                          //
                      }
                      and the contextLoader...

                      Code:
                      public class MyContextLoader extends AbstractContextLoader {
                      
                      	protected static final Log logger = LogFactory.getLog(MyContextLoader.class);
                      	
                      	public static final ServletContext SERVLET_CONTEXT = new MockServletContext();
                      	
                      	protected BeanDefinitionReader createBeanDefinitionReader(final GenericApplicationContext context) {
                      		return new XmlBeanDefinitionReader(context);
                      	}
                      	
                      	public final ConfigurableApplicationContext loadContext(final String... locations) throws Exception {
                      
                      		if (logger.isDebugEnabled()) {
                      			logger.debug("Loading ApplicationContext for locations ["
                      					+ StringUtils.arrayToCommaDelimitedString(locations) + "].");
                      		}
                      
                      		final GenericWebApplicationContext webContext = new GenericWebApplicationContext();
                      		servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, webContext);
                      		webContext.setServletContext(SERVLET_CONTEXT);
                      		createBeanDefinitionReader(webContext).loadBeanDefinitions(locations);
                      		AnnotationConfigUtils.registerAnnotationConfigProcessors(webContext);
                      		webContext.refresh();
                      		webContext.registerShutdownHook();
                      		return webContext;
                      	}
                      	
                      	@Override
                      	protected String getResourceSuffix() {
                      		return "-context.xml";
                      	}
                      
                      }

                      Comment


                      • #12
                        Hi JuanManual32

                        Many thanks for your help - this seems to do the trick.The loader makes the WebApplicationContext available resolving both the XmlViewResolver and RequestContext errors I was seeing and the dependancyinjection works.

                        Here's your ContextLoader with a couple of tweaks :
                        Code:
                        public class MyContextLoader extends AbstractContextLoader {
                            protected static final Log logger = LogFactory.getLog(MyContextLoader.class);
                        	
                        	public static final ServletContext SERVLET_CONTEXT = new MockServletContext("/WebContent", new FileSystemResourceLoader());
                        	
                        	protected BeanDefinitionReader createBeanDefinitionReader(final GenericApplicationContext context) {
                        		return new XmlBeanDefinitionReader(context);
                        	}
                        	
                        	public final ConfigurableApplicationContext loadContext(final String... locations) throws Exception {
                        
                        		if (logger.isDebugEnabled()) {
                        			logger.debug("Loading ApplicationContext for locations ["
                        					+ StringUtils.arrayToCommaDelimitedString(locations) + "].");
                        		}
                        
                        		final GenericWebApplicationContext webContext = new GenericWebApplicationContext();
                        		SERVLET_CONTEXT.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, webContext);
                        		webContext.setServletContext(SERVLET_CONTEXT);
                        		createBeanDefinitionReader(webContext).loadBeanDefinitions(locations);
                        		AnnotationConfigUtils.registerAnnotationConfigProcessors(webContext);
                        		webContext.refresh();
                        		webContext.registerShutdownHook();
                        		return webContext;
                        	}
                        	
                        	protected String getResourceSuffix() {
                        		return "-context.xml";
                        	}
                        
                        }
                        and a test snippet .....

                        Code:
                        @RunWith(.....
                        @ContextConfiguration(loader=MyContextLoader.class, locations={"classpath:my-application-context.xml"})
                        public class MyControllerTest extends AbstractTransactionalJUnit4SpringContextTests {
                        
                        	@Autowired
                        	protected hplMetricsController hplMetricsController;
                        	
                        	private ServletContext servletContext;
                        	private  MockPageContext pageContext;
                        	private  MockServletConfig servletConfig;
                        	private  MockHttpSession session;
                        	private  MockHttpServletRequest request;
                        	private  MockHttpServletResponse response;
                                private  WebApplicationContext wac;
                        
                        	
                        	@Test
                        	public void setupMocks() throws Exception {
                        		wac = WebApplicationContextUtils.getRequiredWebApplicationContext(MyContextLoader.SERVLET_CONTEXT);
                        		servletContext = wac.getServletContext();
                                        pageContext = new MockPageContext(servletContext);
                                        servletConfig = (MockServletConfig) pageContext.getServletConfig();
                        		session = (MockHttpSession)pageContext.getSession();		
                        		request = (MockHttpServletRequest) pageContext.getRequest();
                        		response = (MockHttpServletResponse)pageContext.getResponse();
                        Thanks to everyone for their time and assistance....... Geoff

                        Comment


                        • #13
                          Hi, I have tried this solution but for me it can never find the context.xml file.

                          I have a file named /webapp/securityContext/xml

                          Code:
                          @RunWith(SpringJUnit4ClassRunner.class)
                          @ContextConfiguration(loader=MockServletContextWebContextLoader.class, locations={"/securityContext.xml"})
                          And the config loader class.

                          Code:
                          @Override
                          	public final ConfigurableApplicationContext loadContext(String... locations) throws Exception {
                          		ConfigurableWebApplicationContext context = new XmlWebApplicationContext();
                          		context.setServletContext(new MockServletContext("/webapp", new FileSystemResourceLoader()));
                          		context.setConfigLocations(locations);
                          		context.refresh();
                          		AnnotationConfigUtils.registerAnnotationConfigProcessors((BeanDefinitionRegistry) context.getBeanFactory());
                          		context.registerShutdownHook();
                          		return context;
                          	}
                          
                          	@Override
                          	protected String getResourceSuffix() {
                          		System.out.println("USED???????");
                          		return "Context.xml";
                          	}
                          I have tried all sorts of paths, but it never can find the file.

                          Anyone know a solution?

                          Thanks,
                          Coenos

                          Comment


                          • #14
                            Hi Coenos,

                            By default, the Spring TestContext Framework assumes that resource locations are in the classpath. If you want to reference an XML configuration file in the filesystem, you'll need to use the "file:" prefix.

                            If you have a file named /webapp/securityContext.xml, I would assume that means it's in a "webapp" folder within your project. In that case, the following should work:

                            Code:
                            @RunWith(SpringJUnit4ClassRunner.class)
                            @ContextConfiguration(
                                locations="file:webapp/securityContext.xml",
                                loader=MockServletContextWebContextLoader.class)
                            If you're using the Maven conventions for folders, your "webapp" folder would be under "src/main/webapp" in your current project, and you should store configuration files somewhere under "WEB-INF" (e.g., "src/main/webapp/WEB-INF/securityContext.xml"). In that case, the following should work:

                            Code:
                            @RunWith(SpringJUnit4ClassRunner.class)
                            @ContextConfiguration(
                                locations="file:src/main/webapp/WEB-INF/securityContext.xml",
                                loader=MockServletContextWebContextLoader.class)

                            Hope this helps!

                            Sam

                            Comment

                            Working...
                            X