I am writing junits for a rest controller. I want only minimal context to be loaded which is related to the controller and I think that is how @WebMvcTest
loads the context. But the junit is loading complete Spring context and it is failing as some of the beans can not be created.
I have searched and read through many questions on stackoverflow and none of the solutions worked to exclude specific configuration. How can I load a minimal context when writing junits for controllers? Or is there any way to exclude some configuration classes? I am using Spring-boot 2.2.2.RELEASE, Java 8 and Junit 4.
Junit (where I have tried to exclude loading of some beans and configurations but it doesn't work):
@RunWith(SpringRunner.class)
@WebMvcTest(controllers = OrderController.class, excludeFilters = {@Filter(classes = Configuration.class), @Filter(type = FilterType.REGEX, pattern = "com\\.foo\\..*")})
@TestPropertySource(properties = { "spring.cloud.config.server.bootstrap:false" })
public class OrderControllerTest {
@MockBean
private OrderService orderService;
@Autowired
private MockMvc mockMvc;
@Test
public void test() throws Exception {
mockMvc.perform(get("/internal/order/123"));
// Further code to verify the response
}
}
Controller
@Slf4j
@Validated
@RestController
@RequestMapping("/internal")
public class OrderController {
@Autowired
private OrderService orderService;
@GetMapping(value = "/order/{orderId}", produces = { MediaType.APPLICATION_JSON_VALUE })
public ResponseEntity<RegularContributionOrder> retrieveRegularContributionOrder(@NotNull @PathVariable("orderId") String orderId)
throws OrderNotFoundException {
RegularContributionOrder order = orderService.retrieve(orderId);
return new ResponseEntity<RegularContributionOrder>(order, HttpStatus.OK);
}
}
Configuration class which I want to exclude from context loading
@Slf4j
@Configuration
@EnableAspectJAutoProxy
@ImportResource({ "classpath:spring/service-config-one.xml", "classpath:spring/service-config-two.xml" })
public class OrderServiceConfig {
@Bean
public MessageSource messageSource() {
ReloadableResourceBundleMessageSource messageSource = new ReloadableResourceBundleMessageSource();
messageSource.setBasename("classpath:resourcebundles/error-messages.properties");
messageSource.setDefaultEncoding("UTF-8");
return messageSource;
}
@Bean
public ObjectMapper objectMapper() {
ObjectMapper mapper = new ObjectMapper();
return mapper;
}
}
Spring boot main class:
@EnableJms
@EnableAspectJAutoProxy
@ComponentScan(basePackages = { "com.foo.services", "com.bar" })
@SpringBootApplication(exclude = { SomeConfiguration.class})
public class BootApplication extends SpringBootServletInitializer {
@Override
protected final SpringApplicationBuilder configure(final SpringApplicationBuilder application) {
return application.sources(BootApplication .class);
}
public static void main(final String[] args) {
TimeZone.setDefault(TimeZone.getTimeZone("UTC"));
SpringApplication.run(BootApplication.class, args);
}
}
Your use of @ComponentScan
has disabled the filters that are used by @WebMvcTest
to limit the types of components that are found by scanning.
You should remove @ComponentScan
from your main application class and use the basePackages
attribute on @SpringBootApplication
instead.
You should also move @EnableJms
and @EnableAspectJAutoProxy
to a separate @Configuration
class so that they are not enabled when using @WebMvcTest
. Alternatively, you may be able to remove them entirely as they are covered by Spring Boot’s auto-configuration.