views:

1140

answers:

1

The following test illustrates that this test bean is initialized twice by Spring. I'm hoping someone can tell me why this is so, since it should only be once. Here's the test:

import org.apache.log4j.Logger;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;


@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {} )
public class TestAfterPropsSet implements InitializingBean {

private static final Logger logger = Logger.getLogger(TestAfterPropsSet.class);

@Test
public void test1() {
 logger.debug("Test1");
}

@Test
public void test2() {
 logger.debug("Test2");  
}

public void afterPropertiesSet() throws Exception {
 logger.debug("Bean Initialized");  
}
} // end class

Here's the bean file:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="
     http://www.springframework.org/schema/beans
      http://www.springframework.org/schema/beans/spring-beans.xsd"&gt;
</beans>

and here's the output:

2009-10-13 21:20:04,393 [TestAfterPropsSet.java 26] DEBUG - Bean Initialized
2009-10-13 21:20:04,393 [TestAfterPropsSet.java 17] DEBUG - Test1
2009-10-13 21:20:04,393 [TestAfterPropsSet.java 26] DEBUG - Bean Initialized
2009-10-13 21:20:04,393 [TestAfterPropsSet.java 22] DEBUG - Test2
+4  A: 

It's not a Spring convention. You should be following JUnit conventions, i.e. suite-wide initialization or deconstruction should be done in @BeforeClass and @AfterClass accordingly, or you can use @Autowire and let Spring handle the object's scope.

A new suite will be constructed for each test. This is more apparent in JUnit3 where you had to create a new suite using a specified test name.

Take a look at the JavaDoc:

The Test annotation tells JUnit that the public void method to which it is attached can be run as a test case. To run the method, JUnit first constructs a fresh instance of the class then invokes the annotated method. Any exceptions thrown by the test will be reported by JUnit as a failure. If no exceptions are thrown, the test is assumed to have succeeded.

Your use case is a bit puzzling since your test isn't actually doing anything and there is no bean, which you reference. By default, Spring beans are declared with the default scope="singleton" attribute, so had you actually declared a bean, it would have been a cached singleton. However, this has nothing to do with method execution.

Droo
notice: "implements InitializingBean" makes it a bean. Or at least I assume by name. And the fact that I can @Autowire fields and such into it.The problem with @BeforeClass is that it executes before Spring does injection into the test class. Since I like to inject test resources this is often a problem. @Before and such also execute before inject but execute for every test. The best I've found is to use afterPropertiesSet() from InitiliazingBean interface and do any setup required with inject resources there. The problem I discovered is that afterPropertiesSet is run before each test.
harschware
That makes a little more sense. I didn't catch the rest of your code before it was edited it to include the formatting. I'm pretty sure that you can use lazy-init="true" to make Spring instantiate on demand in @BeforeClass or @Before using a BeanFactory, but that doesn't solve the re-initializing. Maybe this is just my opinion, but I don't think there's a problem in re-initializing unless there's a code constraint.
Droo
Correction to my comment: "@Before and such also execute before inject" is not true. I don't think that changes much with this issue though.
harschware