1 /*
2  * Copyright 2002-2008 the original author or authors.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package org.springframework.test.context.support;
18 
19 import org.apache.commons.logging.Log;
20 import org.apache.commons.logging.LogFactory;
21 
22 import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
23 import org.springframework.core.Conventions;
24 import org.springframework.test.context.TestContext;
25 
26 /**
27  * <code>TestExecutionListener</code> which provides support for dependency
28  * injection and initialization of test instances.
29  *
30  * @author Sam Brannen
31  * @author Juergen Hoeller
32  * @since 2.5
33  */
34 public class DependencyInjectionTestExecutionListener extends AbstractTestExecutionListener {
35 
36 	/**
37 	 * Attribute name for a {@link TestContext} attribute which indicates
38 	 * whether or not the dependencies of a test instance should be
39 	 * <em>reinjected</em> in
40 	 * {@link #beforeTestMethod(TestContext) beforeTestMethod()}. Note that
41 	 * dependencies will be injected in
42 	 * {@link #prepareTestInstance(TestContext) prepareTestInstance()} in any
43 	 * case.
44 	 * <p>Clients of a {@link TestContext} (e.g., other
45 	 * {@link org.springframework.test.context.TestExecutionListener TestExecutionListeners})
46 	 * may therefore choose to set this attribute to signal that dependencies
47 	 * should be reinjected <em>between</em> execution of individual test
48 	 * methods.
49 	 * <p>Permissible values include {@link Boolean#TRUE} and {@link Boolean#FALSE}.
50 	 */
51 	public static final String REINJECT_DEPENDENCIES_ATTRIBUTE = Conventions.getQualifiedAttributeName(
52 			DependencyInjectionTestExecutionListener.class, "reinjectDependencies");
53 
54 	private static final Log logger = LogFactory.getLog(DependencyInjectionTestExecutionListener.class);
55 
56 
57 	/**
58 	 * Performs dependency injection on the
59 	 * {@link TestContext#getTestInstance() test instance} of the supplied
60 	 * {@link TestContext test context} by
61 	 * {@link AutowireCapableBeanFactory#autowireBeanProperties(Object, int, boolean) autowiring}
62 	 * and
63 	 * {@link AutowireCapableBeanFactory#initializeBean(Object, String) initializing}
64 	 * the test instance via its own
65 	 * {@link TestContext#getApplicationContext() application context} (without
66 	 * checking dependencies).
67 	 * <p>The {@link #REINJECT_DEPENDENCIES_ATTRIBUTE} will be subsequently removed
68 	 * from the test context, regardless of its value.
69 	 */
70 	@Override
prepareTestInstance(final TestContext testContext)71 	public void prepareTestInstance(final TestContext testContext) throws Exception {
72 		if (logger.isDebugEnabled()) {
73 			logger.debug("Performing dependency injection for test context [" + testContext + "].");
74 		}
75 		injectDependencies(testContext);
76 	}
77 
78 	/**
79 	 * If the {@link #REINJECT_DEPENDENCIES_ATTRIBUTE} in the supplied
80 	 * {@link TestContext test context} has a value of {@link Boolean#TRUE},
81 	 * this method will have the same effect as
82 	 * {@link #prepareTestInstance(TestContext) prepareTestInstance()};
83 	 * otherwise, this method will have no effect.
84 	 */
85 	@Override
beforeTestMethod(final TestContext testContext)86 	public void beforeTestMethod(final TestContext testContext) throws Exception {
87 		if (Boolean.TRUE.equals(testContext.getAttribute(REINJECT_DEPENDENCIES_ATTRIBUTE))) {
88 			if (logger.isDebugEnabled()) {
89 				logger.debug("Reinjecting dependencies for test context [" + testContext + "].");
90 			}
91 			injectDependencies(testContext);
92 		}
93 	}
94 
95 	/**
96 	 * Performs dependency injection and bean initialization for the supplied
97 	 * {@link TestContext} as described in
98 	 * {@link #prepareTestInstance(TestContext) prepareTestInstance()}.
99 	 * <p>The {@link #REINJECT_DEPENDENCIES_ATTRIBUTE} will be subsequently removed
100 	 * from the test context, regardless of its value.
101 	 * @param testContext the test context for which dependency injection should
102 	 * be performed (never <code>null</code>)
103 	 * @throws Exception allows any exception to propagate
104 	 * @see #prepareTestInstance(TestContext)
105 	 * @see #beforeTestMethod(TestContext)
106 	 */
injectDependencies(final TestContext testContext)107 	protected void injectDependencies(final TestContext testContext) throws Exception {
108 		Object bean = testContext.getTestInstance();
109 		AutowireCapableBeanFactory beanFactory = testContext.getApplicationContext().getAutowireCapableBeanFactory();
110 		beanFactory.autowireBeanProperties(bean, AutowireCapableBeanFactory.AUTOWIRE_NO, false);
111 		beanFactory.initializeBean(bean, testContext.getTestClass().getName());
112 		testContext.removeAttribute(REINJECT_DEPENDENCIES_ATTRIBUTE);
113 	}
114 
115 }
116