Search code examples
springspring-testspring-boot-test

@webMvcTest is not excluding and loading beans marked as @Repository


I've a @RestController which has only one dependency in field @Autowire that dependency is @component, that component Class definition has some autowired fields which are @service and those services have some @repositories.

In this whole flow I've kafka, Quartz, Cassandra and DB2 So when I was creating a Unit test case for my controller, I dont want to setup whole application. so I decided to use @webMvcTest and used @MockBean on my only one dependency of controller class.

But my Test is throwing and exception because its trying to create a Dao bean, which is marked as @repository.

@ActiveProfiles("test")
@WebMvcTest(controllers = MyControllerTest .class)
class MyControllerTest {

    @MockBean
    MyControllerDependency dependency;

    @Autowired
    MockMvc mockMvc;

    @Test
    void test_something() throws Exception {
       assert(true);
    }
}

Here is oversimplified version of code

@Component
class MyControllerDependency { 
    @AutoiWired
    MyCustomService service;
}

@Service
class MyCustomService{

   @Autowired
   MyCustomDao dao;
}

@Repository
class MyCustomDao{
    @Autowired
    private JdbcTemplate template;
}

I'm getting following exception in test.

Exception

***************************
APPLICATION FAILED TO START
***************************

Description:

Field template in com.....MyCustomDao`  required a bean of type 'org.springframework.jdbc.core.JdbcTemplate' that could not be found.

Question is, When I'm using @WebMvcTest slice and already mocking the only required dependency MyControllerDependency then why spring test context is trying to load MyCustomDao which is annotated as @Repository.

I can do integration testing with SpringbootTest & AutoconfigureMockMVC, but for writing Junit test just for controller, I need to use WebMvcTest slice. which is creating a problem.


Solution

  • Do you have any @ComponentScan("...") annotation active on your @SpringBootApplication?

    As described in Spring Boot Reference Documentation:

    Another source of confusion is classpath scanning. Assume that, while you structured your code in a sensible way, you need to scan an additional package. Your application may resemble the following code:

    @SpringBootApplication
    @ComponentScan({ "com.example.app", "com.example.another" })
    public class MyApplication {
    
        // ...
    
    }
    

    Doing so effectively overrides the default component scan directive with the side effect of scanning those two packages regardless of the slice that you chose. For instance, a @DataJpaTest seems to suddenly scan components and user configurations of your application. Again, moving the custom directive to a separate class is a good way to fix this issue.

    One solution is to create a seperate @Configuration that is annotated with @ComponentScan. When creating a @WebMvcTest the configuration (and its component scan is ignored).

    @Configuration
    @ComponentScan("com.example.another")
    public class DbConfig {
    }