Vitaly
Vitaly

Reputation:

Spring - Skip init-method in unit test

I would like to test Spring configuration in Junit test case without invoking init-method on configured beans. I could have coded my init-methods to skip actual work based on system property which could have been set in test case but I am looking for a cleaner solution.

Upvotes: 0

Views: 4118

Answers (5)

Paul McKenzie
Paul McKenzie

Reputation: 20096

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.

Upvotes: 0

Vitaly
Vitaly

Reputation:

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();
}

Upvotes: 0

Pablojim
Pablojim

Reputation: 8582

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...

Upvotes: 0

laz
laz

Reputation: 28638

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?

Upvotes: 1

dustmachine
dustmachine

Reputation: 10814

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?

Upvotes: 3

Related Questions