20

I created multiple spring-boot testing class, (with spring-boot 1.4.0).

FirstActionTest.java:

@RunWith(SpringRunner.class)
@WebMvcTest(FirstAction.class)
@TestPropertySource("classpath:test-application.properties")
public class FirstActionTest {
    @Autowired
    private MockMvc mvc;

    // ...
}

SecondActionTest.java:

@RunWith(SpringRunner.class)
@WebMvcTest(SecondAction.class)
@TestPropertySource("classpath:test-application.properties")
public class SecondActionTest {
    @Autowired
    private MockMvc mvc;

    // ...
}

When run test via:

mvn test

It seems created a spring test context for each testing class, which is not necessary I guess.

The question is:

  • Is it possible to share a single spring test context among multiple testing class, and if yes, how?
Eric
  • 22,183
  • 20
  • 145
  • 196
  • yes it is possible. http://stackoverflow.com/a/8502023/410677 – kuhajeyan Oct 25 '16 at 10:05
  • @kuhajeyan The link is for xml based configuration, even in spring2.5 we can do that quite easily. But with spring-boot, usually there is no configuration file for context, not sure how to adapt that into spring-boot. – Eric Oct 25 '16 at 10:09
  • 1
    Saw on their documentation that it caches the context but not working for me, it reloads for every test class. > Spring’s test framework will cache application contexts between tests. Therefore, as long as your tests share the same configuration (no matter how it’s discovered), the potentially time consuming process of loading the context will only happen once. http://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-testing.html#boot-features-testing-spring-boot-applications-detecting-config – Ahmed Dec 08 '16 at 11:33

1 Answers1

16

By using two different classes with @WebMvcTest (i.e @WebMvcTest(FirstAction.class) and @WebMvcTest(SecondAction.class)) you are specifically indicating that you want different application contexts. You can't share a single context in this case because each context contains a different set of beans. If you're controller beans are fairly well behaved then the context should be relatively quick to create and you shouldn't really have a problem.

If you really want to have a context that can be cached and shared across all web tests, then you need to ensure that it contains exactly the same bean definitions. Two options that spring to mind:

1) Use @WebMvcTest without any controller specified.

FirstActionTest:

@RunWith(SpringRunner.class)
@WebMvcTest
@TestPropertySource("classpath:test-application.properties")
public class FirstActionTest {
    @Autowired
    private MockMvc mvc;

    // ...
}

SecondActionTest:

@RunWith(SpringRunner.class)
@WebMvcTest
@TestPropertySource("classpath:test-application.properties")
public class SecondActionTest {
    @Autowired
    private MockMvc mvc;

    // ...
}

2) Don't use @WebMvcTest at all so you get an application context that contains all beans (not just web concerns)

FirstActionTest:

@RunWith(SpringRunner.class)
@SpringBootTest
@TestPropertySource("classpath:test-application.properties")
public class FirstActionTest {
    @Autowired
    private MockMvc mvc; // use MockMvcBuilders.webAppContextSetup to create mvc

    // ...
}

SecondActionTest:

@RunWith(SpringRunner.class)
@SpringBootTest
@TestPropertySource("classpath:test-application.properties")
public class SecondActionTest {
    @Autowired
    private MockMvc mvc; // use MockMvcBuilders.webAppContextSetup to create mvc

    // ...
}

Keep in mind that a cached context can make running multiple tests faster, but if you're repeatedly running a single test at development time, you're paying the cost of creating a lot of beans that then immediately get thrown away.

Phil Webb
  • 8,119
  • 1
  • 37
  • 37
  • 2
    For autowiring MockMvc you can also add annotation `@AutoConfigureMockMvc` when doing `@SpringBootTest` – Ahmed Dec 09 '16 at 07:45
  • Thanks for the clear explanation, I think `option 1)` would be cool for projects that has multiple spring mvc tests. It would be helpful if these information could be included in spring-boot documents. – Eric Dec 09 '16 at 09:15
  • When I use `@WebMvcTest` directly without controller class specified for a test, and start `mvn test`, it failed to found dependencies autowired, and the error look like this: `Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'sportsFieldAction': Unsatisfied dependency expressed through field 'dao': No qualifying bean of type [com.sportslight.dao.SportsFieldDao] found for dependency [com.sportslight.dao.SportsFieldDao]`, thus it seems context failed to find beans, don't know why. – Eric Dec 10 '16 at 04:27
  • @Ahmed Did you succeed with the `solution 1)` in the answer ? I got error ... as described in above comment. – Eric Dec 10 '16 at 04:31
  • @EricWang solution 2 worked for me, didn't went for solution 1, as I wanted to load the context not just controller slice. – Ahmed Dec 10 '16 at 09:50
  • @Ahmed With `solution 2)` I got another error, as `Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [org.springframework.test.web.servlet.MockMvc] found for dependency [org.springframework.test.web.servlet.MockMvc]:` – Eric Dec 10 '16 at 17:00
  • @EricWang add this annotation `@AutoConfigureMockMvc`. – Ahmed Dec 11 '16 at 09:16
  • @Ahmed Thanks, adding `@AutoConfigureMockMvc` eliminate errors in `solution 2)`, but not sure whether they actually shared a single context from the log. – Eric Dec 11 '16 at 15:49
  • @EricWang its working for me, the context loads only once. If you are seeing Spring boot banner once then the context is loaded only once. – Ahmed Dec 11 '16 at 17:12
  • @Ahmed I saw it 4 times for 4 tests ... guess it's not working for me, don't know why, I am tired of this issue, I think I would just keep with my original code. – Eric Dec 11 '16 at 17:31
  • 1
    Just 2 more things to try before you give up, you should be using spring boot 1.4.2, define all the `@MockBean` in a base class, so all classes should have same `@MockBean` even if they dont need it. – Ahmed Dec 12 '16 at 07:48