I would like to test Spring configuration in Junit test case without invoking init-method on configured beans. I could of coded my init-methods to skip actual work based on system property which could of been set in test case but I am looking for a cleaner solution.
Are your JUnit tests using the same Spring context configuration files? I'm guessing the answer is yes... it will simplify the problem if your tests use an alternate spring config.
One of the cleanest approaches I've used utilizes some handy annotations, like so:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration
public class MovieServiceTest {
// ...
}
Spring calls this the "TestContext framework" and the JUnit tests will look for a context config file having, for the above example, the name "MovieServiceTest-context.xml"
You could then define the bean without the init-method. Although... wouldn't you want to test that, too?
Is this an init method specified by the attribute init-method of bean in Spring's configuration XML? If so, couldn't you use a different context XML for running tests from what you use in production to achieve this?
You could go a bit old-school and extend the class being tested and override the init method.
Or you could refactor a bit and inject a init strategy object that the init method uses.
I prefer the testContext.xml way though...
Decided to answer my own question to share the solution found. Don't like a solution with maintaining another copy of the config file with no init-methods. My solution is not perfect but gets the job done.
public final static String INIT_METHOD_REGEX = "init-method=\"\\w+\"";
public final static String DESTROY_METHOD_REGEX = "destroy-method=\"\\w+\"";
public final static String PROPERTY_REGEX = "\\$\\{[^\\}]+\\}";
private static List<List<String>> subs = new ArrayList<List<String>>();
static {
subs.add(Arrays.asList( new String[] { INIT_METHOD_REGEX, "" }));
subs.add(Arrays.asList( new String[] { DESTROY_METHOD_REGEX, "" }));
subs.add(Arrays.asList( new String[] { PROPERTY_REGEX, "" }));
}
static public void testSpringConfig(String configFile) throws IOException {
URL springXml = Thread.currentThread().getContextClassLoader().getResource(configFile);
InputStream is = springXml.openStream();
byte[] buffer = new byte[8192];
int readBytes;
ByteArrayOutputStream baos = new ByteArrayOutputStream();
while ((readBytes = is.read(buffer)) != -1)
baos.write(buffer, 0, readBytes);
String content = baos.toString();
for (List<String> s : subs)
content = content.replaceAll(s.get(0), s.get(1));
ByteArrayInputStream bais = new ByteArrayInputStream(content.getBytes());
InputSource isrc = new InputSource(bais);
GenericApplicationContext ctx = new GenericApplicationContext();
XmlBeanDefinitionReader xmlReader = new XmlBeanDefinitionReader(ctx);
xmlReader.setValidationMode(XmlBeanDefinitionReader.VALIDATION_NONE);
xmlReader.loadBeanDefinitions(isrc);
ctx.refresh();
ctx.start();
ctx.close();
}
Is this unit testing or integration testing? If it is unit testing then you shouldn't be loading up the context and hence you don't need to worry about the init method. If it is integration testing, by which I mean any testing that validates the interaction between several of your classes, then you need to make sure that the init method really is called to ensure a valid test.
All that said though, the previous chap hit the nail on the head, use a different context that doesn't invoke the init methods.