I have a static Spring 3.2.4 bean with a protected @PostConstruct method that loads data from a DB when initializing.
When creating a jUnit test, in my test methods, I would like to setup the data in the DB to appropriately test the bean. However, given that the bean is instantiated prior to my test methods, I don't know how to request Spring to defer instantiation of the bean until the method is complete.
Given that the @PostConstruct method is protected, I cannot call it directly to re-initialize the bean, unless I use reflection.
Is there another way to do this, or is reflection the only way? Does Spring have any Util classes to make it easier or do I have to use standard java reflection?
You can always start the context programmatically for such use case. Be aware that you're in charge of the lifecycle of the context in this case. The following pseudo-code illustrates this:
@Test
public void yourTest() {
// setup your database
ConfigurableApplicationContext context =
new ClassPathXmlApplicationContext("/org/foo/your-context.xml");
// Or new AnnotationConfigApplicationContext(YourConfig.class)
try {
YourBean bean = context.getBean("beanId");
// Assertions
} finally {
context.close();
}
}
You probably need Spring to initialize your database. You could for instance use the regular Spring test context support to initialize only the beans you require for the database setup and start another context programmatically to assert your service. If that context needs some services that were used for the database initialization, you can start a child context instead, something like
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration // for instance FooTest-context.xml
public class FooTest {
@Autowired
private ApplicationContext mainContext;
@Test
public void yourTest() {
// setup your database
ClassPathXmlApplicationContext context =
new ClassPathXmlApplicationContext();
context.setParent(mainContext);
context.setConfigLocation("/org/foo/your-context.xml");
context.refresh();
try {
YourBean bean = context.getBean("beanId");
// Assertions
} finally {
context.close();
}
}
}
If that's becoming a recurrent use case you can create a template method that start the container and invoke a callback interface. That way you can share the context lifecycle management at a central place.
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