17

I am trying to create spring-mvc tests using Spring 3.2.1. Following some tutorials, I thought this would be straight-forward.

Here is my test:

@RunWith( SpringJUnit4ClassRunner.class )
@ContextConfiguration( loader = AnnotationConfigContextLoader.class, classes = { JpaTestConfig.class } )
@WebAppConfiguration
public class HomeControllerTest {

    @Resource
    private WebApplicationContext webApplicationContext;

    private MockMvc mockMvc;

    @Test
    public void testRoot() throws Exception {
        mockMvc.perform(get("/").accept(MediaType.TEXT_PLAIN)).andDo(print())
            // print the request/response in the console
            .andExpect(status().isOk()).andExpect(content().contentType(MediaType.TEXT_PLAIN))
            .andExpect(content().string("Hello World!"));
    }

    @Before
    public void setUp() {
        mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).build();
    }
}

Here is my relevant pom.xml:

<dependency>
    <groupId>org.hamcrest</groupId>
    <artifactId>hamcrest-all</artifactId>
    <version>1.3</version>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>4.10</version>
    <scope>test</scope>
<exclusions>
    <exclusion>
        <artifactId>hamcrest-core</artifactId>
        <groupId>org.hamcrest</groupId>
    </exclusion>
</exclusions>
</dependency>
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-test</artifactId>
    <version>3.2.1.RELEASE</version>
</dependency>

I have the following test configuration class:

@Configuration
@EnableTransactionManagement
@ComponentScan( basePackages = { "com.myproject.service", "com.myproject.utility",
        "com.myproject.controller" } )
@ImportResource( "classpath:applicationContext.xml" )
public class JpaTestConfig {

    @Bean
    public LocalContainerEntityManagerFactoryBean entityManagerFactoryBean() {
    ...
    }

    // various other services/datasource but not controllers
}

It is my understanding that adding @WebAppConfiguration will force Spring to inject it. But when I run this test from within Eclipse I get:

Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [org.springframework.web.context.WebApplicationContext] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)} at org.springframework.beans.factory.support.DefaultListableBeanFactory.raiseNoSuchBeanDefinitionException(DefaultListableBeanFactory.java:967) at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:837) at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:749) at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:486)

Update - I had to change my Test Java Configuration class

@Configuration
@EnableWebMvc
@ComponentScan( basePackages = { "...." } )
@EnableTransactionManagement
@ImportResource( "classpath:applicationContext.xml" )
public class JpaTestConfig extends WebMvcConfigurationSupport {

However, the problem is now that I can call my REST service, but it is invoking some other services, including database calls. What is the preferred way to just test the call and a mocked response. I would like to test valid and invalid conditions.

GreenGiant
  • 4,930
  • 1
  • 46
  • 76
sonoerin
  • 5,015
  • 23
  • 75
  • 132

4 Answers4

26

In my case problem has been solved by replacing:

@ContextConfiguration(loader = AnnotationConfigContextLoader.class, classes = { ... })

with

@ContextConfiguration(loader = AnnotationConfigWebContextLoader.class, classes = { ... })

Notice the Web in the loader class name. With the previous loader, the GenericApplicationContext has been injected despite @WebAppConfiguration annotation.

fracz
  • 20,536
  • 18
  • 103
  • 149
  • 1
    Awesome !! I'm using Spring 4.2 and searched so much to solve this issue. Added `@WebAppConfiguration` also but it was not working. This solved my issue. – Mital Pritmani Aug 18 '15 at 13:16
  • This is exactly the right fix for my problem! Also as alternative, I simple removed the "loader" from '@ContextConfiguration', so that AnnotationConfigContextLoader won't colide with '@WebAppConfiguration' – dchang Sep 05 '17 at 00:45
6

The below set-up uses only Java configuration classes and works fine for me.

@WebAppConfiguration
@ContextConfiguration(classes = TestApplicationContext.class)
public class MyClassTest {

    private MockMvc mockMvc;

    @Autowired
    private WebApplicationContext wac;

    @Before
    public void setUp() {
        mockMvc = webAppContextSetup(wac).build();
    }
    ....       
}

@Configuration
public class TestApplicationContext {

    @Bean
    public MyBean myBeanId(){
        return Mockito.mock(MyBean.class);
    }
    ....
}

The mere presence of @WebAppConfiguration on a test class ensures that a WebApplicationContext will be loaded for the test using a default path to the root of the web application. Therefore you can autowire the WebApplicationContext and use it to set up the mockMvc.

Note that the @WebAppConfiguration must be used in conjunction with @ContextConfiguration within the test class.

puglieseweb
  • 91
  • 1
  • 3
1

Why don't you add this annotation and see if it works. Replace XXXX-text.xml with your bean mapping xml.

@ContextConfiguration(locations={"classpath:/XXXX-test.xml"})
java_dude
  • 4,038
  • 9
  • 36
  • 61
  • I have my beans mapped in the @Configuration: – sonoerin Apr 21 '13 at 22:07
  • 1
    It turns out I needed to add the following to my test configuration class: @EnableWebMvc @ComponentScan(...) JpaTestConfig extends WebMvcConfigurationSupport – sonoerin Apr 23 '13 at 03:20
  • Good find. Add this update to your question. Or try answering your question with bit detail. – java_dude Apr 23 '13 at 06:18
  • Thank you Java_Dude, I updated but now I have the problem of the REST services throwing exceptions. Is there a way to inject mocked services so they don't blow up? – sonoerin Apr 24 '13 at 01:46
  • Whats the error? This could be because of the dependency? Do you have orm jar in lib? Can you post some code?.. It will be nice if you start another question and provide a link. I will be happy to help you. – java_dude Apr 24 '13 at 04:54
  • java_dude - I created a new question (http://stackoverflow.com/questions/16291398/best-way-to-integration-test-spring-mvc) that asks the best approach to create unit & integration tests. Looking forward to any help you can offer. – sonoerin Apr 30 '13 at 02:46
0

One of the tests is available for local dev support with annotation headers, where I had the similar issue from the question.

The comments are previous version of this test.

@RunWith(SpringJUnit4ClassRunner.class)
/* @EnableJpaAuditing */ /* for jpa dates */ /* it should be defined only once, 
because 'jpaAuditingHandler' defined in null on application startup */
@EntityScan(basePackageClasses = { EnableJpaAuditing.class, Jsr310JpaConverters.class })
//@ProfileValueSourceConfiguration(Application.class)
//@ContextConfiguration(loader = AnnotationConfigContextLoader.class)
@ContextConfiguration(loader = AnnotationConfigWebContextLoader.class)
//@PropertySource("classpath:application.properties")
@TestPropertySource(locations = "classpath:application.properties")
//@WebAppConfiguration
@SpringBootTest
public class JpaTests {/* */}
Oleksii Kyslytsyn
  • 2,458
  • 2
  • 27
  • 43