New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

@PreDestroy method in test instance not executed when run with SpringJUnit4ClassRunner [SPR-4868] #9544

Closed
spring-issuemaster opened this Issue May 27, 2008 · 4 comments

Comments

Projects
None yet
2 participants
@spring-issuemaster
Copy link
Collaborator

spring-issuemaster commented May 27, 2008

Philip Fisher-Ogden opened SPR-4868 and commented

Overview

I have a JUnit 4 class that is being run with the SpringJUnit4ClassRunner. I have two methods annotated with the @PostConstruct and @PreDestroy annotations, which initialize some instance variables (a Selenium-RC browser in this case). The @PostConstruct method is called as expected, i.e., before any of the test methods are executed and before any @Before methods are run. But, the @PreDestroy method does not appear to be called after all of the tests run and after the @After methods.


Example

....

@RunWith(SpringJUnit4ClassRunner.class)
@TestExecutionListeners({
DependencyInjectionTestExecutionListener.class})
@ContextConfiguration(
locations={"classpath:my-test-context.xml"})
public class ExampleTest {
	private static final Logger logger = Logger.getLogger(ExampleTest.class);
	
	@Resource
	private Selenium browser;

    @PostConstruct
    public void setUpBeforeAllTests() {
    	logger.info("starting browser");
        browser.start();
    }

    @PreDestroy
    public void tearDownAfterAllTests() {
    	logger.info("stopping browser");
        browser.stop();
    }

    @Before
    public void setUp() throws Exception {
        logger.info("setUp()");
    }

    @After
    public void tearDown() throws Exception {
        logger.info("tearDown()");
    }
    
    @Test
    public void fakeTest() {
    	// do nothing (for example purposes only)
    }
	
}

Output

2008-05-27 10:52:19.436 INFO  [main] XmlBeanDefinitionReader: Loading XML bean definitions from class path resource [my-test-context.xml]
2008-05-27 10:52:29.301 INFO  [main] GenericApplicationContext: Refreshing org.springframework.context.support.GenericApplicationContext@1fee6fc: display name [org.springframework.context.support.GenericApplicationContext@1fee6fc]; startup date [Tue May 27 10:52:29 PDT 2008]; root of context hierarchy
2008-05-27 10:52:29.301 INFO  [main] GenericApplicationContext: Bean factory for application context [org.springframework.context.support.GenericApplicationContext@1fee6fc]: org.springframework.beans.factory.support.DefaultListableBeanFactory@30d082
2008-05-27 10:52:29.651 INFO  [main] PropertyPlaceholderConfigurer: Loading properties file from class path resource [my-test.properties]
2008-05-27 10:52:30.372 INFO  [main] DefaultListableBeanFactory: Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@30d082: defining beans [org.springframework.beans.factory.config.PropertyPlaceholderConfigurer#0,browser,org.springframework.context.annotation.internalCommonAnnotationProcessor,org.springframework.context.annotation.internalAutowiredAnnotationProcessor,org.springframework.context.annotation.internalRequiredAnnotationProcessor]; root of factory hierarchy
2008-05-27 10:52:30.763 INFO  [main] ExampleTest: starting browser
2008-05-27 10:52:33.977 INFO  [main] ExampleTest: setUp()
2008-05-27 10:52:33.977 INFO  [main] ExampleTest: tearDown()
2008-05-27 10:52:34.218 INFO  [Thread-0] GenericApplicationContext: Closing org.springframework.context.support.GenericApplicationContext@1fee6fc: display name [org.springframework.context.support.GenericApplicationContext@1fee6fc]; startup date [Tue May 27 10:52:29 PDT 2008]; root of context hierarchy
2008-05-27 10:52:34.218 INFO  [Thread-0] DefaultListableBeanFactory: Destroying singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@30d082: defining beans [org.springframework.beans.factory.config.PropertyPlaceholderConfigurer#0,browser,org.springframework.context.annotation.internalCommonAnnotationProcessor,org.springframework.context.annotation.internalAutowiredAnnotationProcessor,org.springframework.context.annotation.internalRequiredAnnotationProcessor]; root of factory hierarchy

Affects: 2.5.4

Issue Links:

  • #6700 ANT does not call destroy-method after tests
  • #12035 When testing using JUnit 4 Suite, destroy-methods are called at the end of the test suite instead of per test

Referenced from: commits e71cd06

2 votes, 4 watchers

@spring-issuemaster

This comment has been minimized.

Copy link
Collaborator Author

spring-issuemaster commented May 27, 2008

Juergen Hoeller commented

Note that the Spring ApplicationContexts managed by SpringJUnit4ClassRunner are shared between all tests with the same context key... So destruction methods could only run after all related tests have executed.

However, there is no corresponding callback in JUnit... This has been reported before in the context of Ant's JUnit runner (#6700). We might be unable to do something about this without extensions to JUnit... In any case, we'll revisit the topic for Spring 3.0.

Juergen

@spring-issuemaster

This comment has been minimized.

Copy link
Collaborator Author

spring-issuemaster commented May 18, 2012

Sam Brannen commented

Philip,

It's fine to use @PostConstruct and @PreDestroy on components within your Spring ApplicationContext; however, in order to tie into test lifecycle callbacks, you should really rely on the features of the underlying test framework.

In your particular case, you should use JUnit's @BeforeClass and @AfterClass annotations instead of @PostConstruct and @PreDestroy within your test class.

I think this will provide you the behavior you're looking for.

Please also see the related discussions in #12035.

If @BeforeClass and @AfterClass don't solve your issue, please let us know.

Thanks,

Sam

@spring-issuemaster

This comment has been minimized.

Copy link
Collaborator Author

spring-issuemaster commented May 18, 2012

Sam Brannen commented

To follow up on my previous comment, the reference manual has been updated for Spring 3.2 to include the following note in the Testing chapter.

        <note>
          <title>JSR-250 Lifecycle Annotations</title>

          <para>In the Spring TestContext Framework
          <interfacename>@PostConstruct</interfacename> and
          <interfacename>@PreDestroy</interfacename> may be used with standard
          semantics on any application components configured in the
          <interfacename>ApplicationContext</interfacename>; however, these
          lifecycle annotations have limited usage within an actual test
          class.</para>

          <para>If a method within a test class is annotated with
          <interfacename>@PostConstruct</interfacename>, that method will be
          executed before any <emphasis>before</emphasis> methods of the
          underlying test framework (e.g., methods annotated with JUnit's
          <interfacename>@Before</interfacename>), and that will apply for
          every test method in the test class. On the other hand, if a method
          within a test class is annotated with
          <interfacename>@PreDestroy</interfacename>, that method will
          <emphasis role="bold">never</emphasis> be executed. Within a test
          class it is therefore recommended to use test lifecycle callbacks
          from the underlying test framework instead of
          <interfacename>@PostConstruct</interfacename> and
          <interfacename>@PreDestroy</interfacename>.</para>
        </note>
@spring-issuemaster

This comment has been minimized.

Copy link
Collaborator Author

spring-issuemaster commented May 18, 2012

Sam Brannen commented

Resolving this issue as Works as Designed.

See previous comments on this page as well as the corresponding commit on GitHub.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment