Announcement Announcement Module
Collapse
No announcement yet.
Missing servlet context in spring tests Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Missing servlet context in spring tests

    Hey everyone.

    I started switching my spring mvc 3.1 application from xml-based configuration to JavaConfig. Everything works fine when I start my application via tomcat:run using maven.

    But when I run tests via spring-test, they fail with the following exception:

    Code:
    ERROR: org.springframework.test.context.TestContextManager - Caught exception while allowing TestExecutionListener [org.springframework.test.context.support.DependencyInjectionTestExecutionListener@2bffef5a] to prepare test instance [net.findme.server.repository.RoleRepositoryTest@9abd962]
    java.lang.IllegalStateException: Failed to load ApplicationContext
    	at org.springframework.test.context.TestContext.getApplicationContext(TestContext.java:157)
    	at org.springframework.test.context.support.DependencyInjectionTestExecutionListener.injectDependencies(DependencyInjectionTestExecutionListener.java:109)
    	at org.springframework.test.context.support.DependencyInjectionTestExecutionListener.prepareTestInstance(DependencyInjectionTestExecutionListener.java:75)
    	at org.springframework.test.context.TestContextManager.prepareTestInstance(TestContextManager.java:321)
    	at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.createTest(SpringJUnit4ClassRunner.java:211)
    	at org.springframework.test.context.junit4.SpringJUnit4ClassRunner$1.runReflectiveCall(SpringJUnit4ClassRunner.java:288)
    	at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15)
    	at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.methodBlock(SpringJUnit4ClassRunner.java:290)
    	at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:231)
    	at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50)
    	at org.junit.runners.ParentRunner$3.run(ParentRunner.java:193)
    	at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:52)
    	at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:191)
    	at org.junit.runners.ParentRunner.access$000(ParentRunner.java:42)
    	at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:184)
    	at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
    	at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:71)
    	at org.junit.runners.ParentRunner.run(ParentRunner.java:236)
    	at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:174)
    	at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50)
    	at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
    	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)
    	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
    	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
    	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)
    Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'defaultServletHandlerMapping' defined in class path resource [org/springframework/web/servlet/config/annotation/DelegatingWebMvcConfiguration.class]: Instantiation of bean failed; nested exception is org.springframework.beans.factory.BeanDefinitionStoreException: Factory method [public org.springframework.web.servlet.HandlerMapping org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport.defaultServletHandlerMapping()] threw exception; nested exception is java.lang.IllegalArgumentException: A ServletContext is required to configure default servlet handling
    	at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:581)
    	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1015)
    	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:911)
    	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:485)
    	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:456)
    	at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:294)
    	at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:225)
    	at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:291)
    	at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:193)
    	at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:585)
    	at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:913)
    	at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:464)
    	at org.springframework.test.context.support.AbstractGenericContextLoader.loadContext(AbstractGenericContextLoader.java:103)
    	at org.springframework.test.context.support.AbstractGenericContextLoader.loadContext(AbstractGenericContextLoader.java:1)
    	at org.springframework.test.context.TestContext.loadApplicationContext(TestContext.java:124)
    	at org.springframework.test.context.TestContext.getApplicationContext(TestContext.java:148)
    	... 24 more
    Caused by: org.springframework.beans.factory.BeanDefinitionStoreException: Factory method [public org.springframework.web.servlet.HandlerMapping org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport.defaultServletHandlerMapping()] threw exception; nested exception is java.lang.IllegalArgumentException: A ServletContext is required to configure default servlet handling
    	at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:169)
    	at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:570)
    	... 39 more
    Caused by: java.lang.IllegalArgumentException: A ServletContext is required to configure default servlet handling
    	at org.springframework.util.Assert.notNull(Assert.java:112)
    	at org.springframework.web.servlet.config.annotation.DefaultServletHandlerConfigurer.<init>(DefaultServletHandlerConfigurer.java:54)
    	at org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport.defaultServletHandlerMapping(WebMvcConfigurationSupport.java:253)
    	at org.springframework.web.servlet.config.annotation.DelegatingWebMvcConfiguration$$EnhancerByCGLIB$$b96b3c4c.CGLIB$defaultServletHandlerMapping$7(<generated>)
    	at org.springframework.web.servlet.config.annotation.DelegatingWebMvcConfiguration$$EnhancerByCGLIB$$b96b3c4c$$FastClassByCGLIB$$c0f11b77.invoke(<generated>)
    	at net.sf.cglib.proxy.MethodProxy.invokeSuper(MethodProxy.java:228)
    	at org.springframework.context.annotation.ConfigurationClassEnhancer$BeanMethodInterceptor.intercept(ConfigurationClassEnhancer.java:280)
    	at org.springframework.web.servlet.config.annotation.DelegatingWebMvcConfiguration$$EnhancerByCGLIB$$b96b3c4c.defaultServletHandlerMapping(<generated>)
    	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    	at java.lang.reflect.Method.invoke(Method.java:601)
    	at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:149)
    	... 40 more
    My test class:

    Code:
    @RunWith(SpringJUnit4ClassRunner.class)
    @TransactionConfiguration(transactionManager="transactionManager", defaultRollback=true)
    @ContextConfiguration(loader=AnnotationConfigContextLoader.class, classes = {DataSourceConfig.class})
    @Transactional
    public class RoleRepositoryTest {
    	/**
    	 * EntityManager for verifying the results of data manip1ulation by the {@code RoleRepository} interface
    	 */
    	@PersistenceContext
    	private EntityManager _entityManager;
    	
    	@Inject
    	private RoleRepository _repository;
    	
    	@Inject
    	private RoleGenerator _roleGenerator;
    	
    	@Test
    	public void testSaveRole() {
    ...	
    	}
    ...
    }

  • #2
    DataSourceConfig:

    Code:
    @Configuration
    @ComponentScan("net.findme.server")
    @PropertySource("classpath:datasource.properties")
    @ImportResource("classpath:spring/datasource-config.xml")
    @EnableTransactionManagement
    public class DataSourceConfig
    {	
    	@Inject
    	Environment env;
    	/**
    	 * @return
    	 */
    	@Bean
    	public PlatformTransactionManager transactionManager() {
    		final JpaTransactionManager transactionManager = new JpaTransactionManager();
    		transactionManager.setEntityManagerFactory(entityManagerFactoryBean().getObject());
    		return transactionManager;
    	}
    	
    	/**
    	 * @return
    	 */
    	@Bean
    	public DriverManagerDataSource dataSource() {
    		final DriverManagerDataSource datasource = new DriverManagerDataSource();
    		datasource.setUsername(env.getProperty("jdbc.username"));
    		datasource.setPassword(env.getProperty("jdbc.password"));
    		datasource.setDriverClassName(env.getProperty("jdbc.driverClassName"));
    		datasource.setUrl(env.getProperty("jdbc.url"));
    		return datasource;
    	}
    	
    	/**
    	 * @return
    	 */
    	@Bean
    	public LocalContainerEntityManagerFactoryBean entityManagerFactoryBean() {
    		final LocalContainerEntityManagerFactoryBean emf = new LocalContainerEntityManagerFactoryBean();
    		emf.setDataSource(dataSource());
    		emf.setPersistenceUnitName(env.getProperty("jdbc.persistenceUnit"));
    		emf.setJpaVendorAdapter(jpaVendorAdapter());
    		return emf;
    	}
    	
    	/**
    	 * @return
    	 */
    	@Bean
    	public JpaVendorAdapter jpaVendorAdapter() {
    		final  HibernateJpaVendorAdapter hibernateJpaVendorAdapter = new HibernateJpaVendorAdapter();
    	    hibernateJpaVendorAdapter.setShowSql(Boolean.parseBoolean(env.getProperty("jdbc.showSql")));
    	    hibernateJpaVendorAdapter.setGenerateDdl(Boolean.parseBoolean(env.getProperty("jdbc.generateDdl")));
    	    hibernateJpaVendorAdapter.setDatabasePlatform(env.getProperty("jdbc.databasePlattform"));
    	    hibernateJpaVendorAdapter.setDatabase(Database.MYSQL);
    	    return hibernateJpaVendorAdapter;
    	}
    }
    WebConfig:

    Code:
    @Configuration
    @EnableWebMvc
    @ComponentScan("net.findme.server.controller")
    public class WebConfig extends WebMvcConfigurerAdapter
    {
    	@Bean
    	public static InternalResourceViewResolver jspViewResolver() {
            InternalResourceViewResolver bean = new InternalResourceViewResolver();
            bean.setPrefix("/WEB-INF/views/");
            bean.setSuffix(".jsp");
            return bean;
    	}
    
    	/* (non-Javadoc)
    	 * @see org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter#addResourceHandlers(org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry)
    	 */
    	@Override
    	public void addResourceHandlers(ResourceHandlerRegistry registry) {
    		registry.addResourceHandler("/resources/**").addResourceLocations("/resources/");
    	}
    ...
    }
    At last, my web.xml:

    Code:
    <?xml version="1.0" encoding="UTF-8"?>
    <web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee"
    	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    	xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
    
    	<!-- The definition of the Root Spring Container shared by all Servlets and Filters -->
       <context-param>
          <param-name>contextClass</param-name>
          <param-value>org.springframework.web.context.support.AnnotationConfigWebApplicationContext</param-value>
       </context-param>
    	<context-param>
    		<param-name>contextConfigLocation</param-name>
    		<param-value>net.findme.server.config</param-value>
    	</context-param>
    	
    	<!-- Creates the Spring Container shared by all Servlets and Filters -->
    	<listener>
    		<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    	</listener>
    
    	<!-- Processes application requests -->
    	<servlet>
    		<servlet-name>rest</servlet-name>
    		<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    		      <init-param>
             <param-name>contextClass</param-name>
             <param-value>org.springframework.web.context.support.AnnotationConfigWebApplicationContext</param-value>
          </init-param>
    		<init-param>
    			<param-name>contextConfigLocation</param-name>
    			<param-value>net.findme.server.config</param-value>
    		</init-param>
    		<load-on-startup>1</load-on-startup>
    	</servlet>
    		
    	<servlet-mapping>
    		<servlet-name>rest</servlet-name>
    		<url-pattern>/</url-pattern>
    	</servlet-mapping>
    	
    	   <!-- Disables servlet container welcome file handling. Needed for compatibility 
          with Servlet 3.0 and Tomcat 7.0 -->
       <welcome-file-list>
          <welcome-file />
       </welcome-file-list>
    </web-app>
    Anyone an idea? I cannot figure out the missing piece..
    Thanks in advance!!
    Markus

    Comment


    • #3
      Have you actually read the stacktrace?

      Code:
      Error creating bean with name 'defaultServletHandlerMapping' defined in class path resource [org/springframework/web/servlet/config/annotation/DelegatingWebMvcConfiguration.class]: Instantiation of bean failed; nested exception is org.springframework.beans.factory.BeanDefinitionStoreException: Factory method [public org.springframework.web.servlet.HandlerMapping org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport.defaultServletHandlerMapping()] threw exception; nested exception is java.lang.IllegalArgumentException: A ServletContext is required to configure default servlet handling
      You are trying to instantatie web based beans outside of a web context for some beans this isn't going to work. If you want to test this you will need to fake (mock or stub) your web environment.

      Comment


      • #4
        Thanks for your reply.
        Yes I did read it, but didn't really understand, because I just adapted my xml configuration into @Bean definitions in @Configuration classes. Thought loading my configuration classes via AnnotationConfigContextLoader in my tests would be sufficient...I'll have a look at the MockServletContext, etc, classes...

        Comment


        • #5
          Does anyone know how to "plug" a ServletContext" into my test?

          Comment


          • #6
            Do you really need it? Make some testConfig class in your test package that pulls in only the beans and configuration you need, and use that in your @ContextConfiguration. There is no need to test the framework or pull in the web context in most cases.

            Comment


            • #7
              Yes I did read it, but didn't really understand, because I just adapted my xml configuration into @Bean definitions in @Configuration classes. Attachment
              Attached Files

              Comment


              • #8
                @wgorder
                Thanks!
                No, I think I don't..The test above is just about testing my data access layer via spring-data-jpa..But even when I just load my DataSourceConfig via "loader=AnnotationConfigContextLoader.class, classes = {DataSourceConfig.class} in my test case", it's still the same exception as above...I have really no Idea, because there's no need to mock a servlet context...I think!...But maybe I'm totally wrong..really need help! :\

                Comment


                • #9
                  Yes I did read it, but didn't really understand, because I just adapted my xml configuration into @Bean definitions in @Configuration classes. Attachment
                  Attached Files

                  Comment


                  • #10
                    The DataSourceConfig you have listed has an import of this xml

                    @ImportResource("classpath:spring/datasource-config.xml")

                    What is the contents of datasource-config.xml? Also where on the classpath is it located, is it in src/main/resources?

                    Comment


                    • #11
                      My datasource-config.xml just contains one line for scanning for spring-data-jpa repositories...

                      <jpa:repositories base-package="net.findme.server.repository"></jpa:repositories>

                      And it's in src/main/resources..:\

                      Comment


                      • #12
                        Well something you are doing in is trying to use a web bean as Marten stated. If its not in the configuration its somethinng you are doing in your test case. Can you provide a small sample application so I can reproduce this? I am doing exactly what it sounds like you are trying to do in mulitiple projects for my integration testing and I don't have this issue.

                        Thanks,

                        Comment


                        • #13
                          This is my testcase, that causes the exception above...

                          Code:
                          @RunWith(SpringJUnit4ClassRunner.class)
                          @ContextConfiguration(loader=AnnotationConfigContextLoader.class, classes = {DataSourceConfig.class})
                          @TransactionConfiguration(transactionManager="transactionManager", defaultRollback=true)
                          @Transactional
                          public class RoleRepositoryTest {
                          	/**
                          	 * EntityManager for verifying the results of data manip1ulation by the {@code RoleRepository} interface
                          	 */
                          	@PersistenceContext
                          	private EntityManager _entityManager;
                          	
                          	@Inject
                          	private RoleRepository _repository;
                          
                          	@Inject
                          	private RoleGenerator _roleGenerator;
                          	
                          	@Test
                          	public void testSaveRole() {
                          		final Role role = _roleGenerator.getRole();
                          		assertNull(role.getPrimaryKey());
                          		assertNull(role.getRoleId());
                          		assertFalse(role.primaryKeyExists());
                          		final Role saved = _repository.save(role);
                          		assertTrue(role.getPrimaryKey() != null);
                          		assertTrue(saved.getPrimaryKey() != null);
                          		assertTrue(role.getPrimaryKey() == saved.getPrimaryKey());
                          		final long id = role.getPrimaryKey();
                          		final TypedQuery<Role> query = _entityManager.createQuery("from Role r where r.roleId = ?1", Role.class);
                          		query.setParameter(1, role.getPrimaryKey());
                          		
                          		final Role result = query.getSingleResult();
                          		assertEquals(result, role);
                          		assertEquals(result.getRoleName(), role.getRoleName());		
                          	}
                          Here's an excerpt of my project folder, if you want to have a look...

                          Thanks!

                          Comment


                          • #14
                            I did not have your database set up and I did not have a chance to use an embedded one to mock it out but on first glance I can see you have

                            @ComponentScan(basePackages = { "net.findme.server" }) on your dbconfig. Remove that line. You already have it in one of your other configs so its not needed and when you pull it in on your test case you are bringing in the web beans.

                            Alternatively if you really want that in that config file create a DbTestConfig.java in your /src/test/java/ that looks like theh one you have but does not have that line. And bring in that config file on your test case. Either way I think that will solve your issue.

                            Thanks,

                            Comment


                            • #15
                              Hi guys,

                              The following are open JIRA issues related to this topic. Feel free to watch them.

                              Regards,

                              Sam

                              Comment

                              Working...
                              X