I am testing my controller given below
@Controller public class MasterController { @GetMapping("/") public String goLoginPage(){ return "index"; } }
I am following this Spring documentation to test my controller. Now, I want to test my controller by just instantiating the web layer and not the whole Spring context as given in the documentation. Below is my code for the same.
@RunWith(SpringRunner.class) @WebMvcTest public class MasterControllerTestWithWebLayer { @Autowired MockMvc mockMvc; @Autowired MasterController masterController; @Before public void setUp() throws Exception { } @After public void tearDown() throws Exception { } @Test public void testLoginHome() throws Exception{ mockMvc.perform(get("/")) .andExpect(status().isOk()) .andExpect(view().name("index")); } }
When I run this test I get the error Unable to find @SpringBootConfiguration,...etc
. But I am confused why it is asking for Spring configuration when we do not want it to instantiate it but want to use only the web layer. Kindly point me to the right direction what is happening here. And also how to fix this. Thanks
Spring @Configuration annotation is part of the spring core framework. Spring Configuration annotation indicates that the class has @Bean definition methods. So Spring container can process the class and generate Spring Beans to be used in the application.
@RunWith(SpringRunner. class) provides a bridge between Spring Boot test features and JUnit. Whenever we are using any Spring Boot testing features in our JUnit tests, this annotation will be required.
@WebMvcTest annotation is used for Spring MVC tests. It disables full auto-configuration and instead apply only configuration relevant to MVC tests. The WebMvcTest annotation auto-configure MockMvc instance as well.
So here is the solution:
The documentation on detecting test configuration says:
The search algorithm works up from the package that contains the test until it finds a @SpringBootApplication or @SpringBootConfiguration annotated class. As long as you’ve structure your code in a sensible way your main configuration is usually found.
So the @SpringBootApplication
class should be higher in the package hierarchy than the test class e.g if test class is in package com.zerosolutions.controller
then @SpringBootApplication
class should be in a package higher than com.zerosolutions.controller
package i.e com.zerosolutions
or com
.
Problem
But in case the @SpringBootApplication
class is at the same level as test class it won't be able to find it i.e com.zerosolutions.general
. In this case you'll get the following error:
java.lang.IllegalStateException: Unable to find a @SpringBootConfiguration, you need to use @ContextConfiguration or @SpringBootTest(classes=...) with your test
Solution
If you are running an integrated test, you can explicitly mention the @SpringBootApplication
class like this
@RunWith(SpringRunner.class) @SpringBootTest(classes={SpringBootApp.class})
But if you want to do unit testing of a controller you don't need to fire up the whole Spring context. You can rather replace @SpringBootTest
with @WebMvcTest(MasterController.class)
. This will instantiate only the web layer with MasterController
and not the whole Spring context.
Problem
But the problem is you will again run into the error we faced earlier:
java.lang.IllegalStateException: Unable to find a @SpringBootConfiguration, you need to use @ContextConfiguration or @SpringBootTest(classes=...) with your test
And @WebMvtTest
does not have a classes
attribute like @SpringBootTest
to explicitly mention the @SpringBootApplication
class. So there are two solutions to this.
Solution
First: Move your application class to a package higher than the test class i.e com.zerosolutions
or com
package.
Second: Mention your @SpringBootApplication
class explicitly like below
@RunWith(SpringRunner.class) @WebMvcTest(MasterController.class) @ContextConfiguration(classes={SpringBootApp.class})
Hope that clears the Spring Test Configuration confusion. Thanks
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With