Reputation: 10667
I was able to set up and successfully run three different test configurations with SpringBoot 1.5.3
Method #1. Importing Bean with use of @Import
annotation
@RunWith(SpringJUnit4ClassRunner.class)
@Import({MyBean.class})
public class MyBeanTest() {
@Autowired
private MyBean myBean;
}
Method #2. Importing Bean with use of @ContextConfiguration
annotation
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = {MyBean.class})
public class MyBeanTest() {
@Autowired
private MyBean myBean;
}
Method #3 (with internal class configuration; based on the official blog post)
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(loader=AnnotationConfigContextLoader.class)
public class MyBeanTest() {
@Configuration
static class ContextConfiguration {
@Bean
public MyBean myBean() {
return new MyBean();
}
}
@Autowired
private MyBean myBean;
}
Taking into account @Import
annotation documentation
Indicates one or more {@link Configuration @Configuration} classes to import.
and the fact that MyBean
is not a configuration class, but a bean class annotated with @Component
annotation it looks like Method #1 is not correct.
From @ContextConfiguration
documentation
{@code @ContextConfiguration} defines class-level metadata that is used to determine how to load and configure an {@link org.springframework.context.ApplicationContext ApplicationContext} for integration tests.
Sounds like it is better applicable to unit tests, but still, should load a kind of a configuration.
Methods #1 and #2 are shorter and simpler. Method #3 looks like a correct way.
Am I right? Are there other criteria why I should use method #3, like performance or something else?
Upvotes: 18
Views: 12080
Reputation: 33091
It really depends if you're using one of the testing annotations Spring Boot offers or if you're building the context from scratch. The core support in Spring Framework requires you to provide a "root configuration" via @ContextConfiguration
. If you're using Spring Boot, it has its own way of detecting the root context to use. By default, the first @SpringBootConfiguration
-annotated type that it finds. In a typical app structure, that's your @SpringBootApplication
at the root of your application's package.
With that in mind, using @ContextConfiguration
with that setup is not a great idea as it would disable that lookup and will do just more than "importing beans".
Assuming that the context has been created for you and you want to add additional beans, there are two main ways:
If you need to selectively import components (on top of the default behaviour of detecting the right context to use), then @Import
is absolutely fine. In the meantime, the Javadoc of @Import
was polished to mention that importing components is absolutely fine and that it isn't specific to @Configuration
classes:
Indicates one or more component classes to import — typically @Configuration classes.
So, method #1 is definitely correct.
If the component is local to the test and you don't need to share it with another test, then an inner @TestConfiguration
can be used. This is also documented in the reference guide.
Upvotes: 2
Reputation: 2349
You actually don't need to specify the loader if you go with option #3. From the doc In addition to the example from the doc you can override the env. with @TestPropertySource if you need to inject properties in the environment without using the real ones.
@RunWith(SpringRunner.class)
// ApplicationContext will be loaded from the
// static nested Config class
@ContextConfiguration
@TestPropertySource(properties = { "timezone = GMT", "port: 4242" })
public class OrderServiceTest {
@Configuration
static class Config {
// this bean will be injected into the OrderServiceTest class
@Bean
public OrderService orderService() {
OrderService orderService = new OrderServiceImpl();
// set properties, etc.
return orderService;
}
}
@Autowired
private OrderService orderService;
@Test
public void testOrderService() {
// test the orderService
}
}
Upvotes: 3