João Matos
João Matos

Reputation: 6920

Test slice with @WebMvcTest is loading a substantial amount of controllers unrelated with the target

I have a spring boot application yielding numerous controllers and my goal is to create an integration test for a specific one. I read that we can achieve a test slice with the @WebMvcTest annotation that loads only what is necessary to deploy the target controller, is this assumption correct? Here is my test:

@RunWith(SpringRunner.class)
@WebMvcTest(
        controllers = {DummyController.class},
)
public class DummyControllerIT {

    @Autowired
    private MockMvc mockMvc;

...

Unfortunately the execution attempts to deploy other controllers/services/repositories that have no relation to the target Controller, which forces me use @MockBean on each of them. I was under the impression that @WebMvcTest would spare me from having an extensive listing of declared controllers/services/repositories with the @MockBean annotation, am I wrong?

If I misinterpreted this and I am expected to use @MockBean on unrelated parts of the application, then why is it better to use @WebMvcTest instead of @SpringBootTest? On the other hand, if I interpreted it correctly what am I missing?


Not sure if it is related but this is my initialiser:

@ComponentScan(scopedProxy = ScopedProxyMode.INTERFACES)
@SpringBootApplication
@EnableTransactionManagement
@EnableGlobalMethodSecurity(prePostEnabled = true)
@EnableScheduling
@EnableCaching
@EnableJpaAuditing
@EnableJpaRepositories(repositoryFactoryBeanClass = EnversRevisionRepositoryFactoryBean.class)
public class Application extends SpringBootServletInitializer {

    @Autowired
    private Environment env;

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }

    @Override
    protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
        return application.sources(Application.class);
    }

    @Bean
    @Primary
    public TaskExecutor threadPoolTaskExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(Integer.parseInt(Objects.requireNonNull(env.getProperty("coreThreadPoolSize"))));
        executor.setMaxPoolSize(Integer.parseInt(Objects.requireNonNull(env.getProperty("maxThreadPoolSize"))));
        executor.initialize();
        return executor;
    }

}

Thank you for your help.

Upvotes: 0

Views: 1253

Answers (1)

Andy Wilkinson
Andy Wilkinson

Reputation: 116051

@WebMvcTest works by disabling full auto-configuration of your application and also filtering its component scanning so that only the parts that are needed are configured. Your main class, Application, is enabling auto-configuration (via @SpringBootApplication) but is also explicitly enabling component scanning as well as caching, security, JPA repositories, etc. @WebMvcTest doesn't switch off these explicitly enabled pieces so you're left having to mock things.

This problem and the recommended way to avoid it is described in the reference documentation. In short, you should move the various @Enable… annotations to separate @Configuration classes that are picked up by component scanning. You may also want to review the need for some of them. For example, @EnableTransactionManagement is covered by auto-configuration.

Your use of @ComponentScan is also problematic as it switches off the filtering that @WebMvcTest requires. Moving it away from the @SpringBootApplication-annotated class should fix this part of the problem.

Upvotes: 5

Related Questions