001/* 002 * Copyright 2002-2018 the original author or authors. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * https://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017package org.springframework.test.context.support; 018 019import org.apache.commons.logging.Log; 020import org.apache.commons.logging.LogFactory; 021 022import org.springframework.beans.factory.config.AutowireCapableBeanFactory; 023import org.springframework.core.Conventions; 024import org.springframework.test.context.TestContext; 025 026/** 027 * {@code TestExecutionListener} which provides support for dependency 028 * injection and initialization of test instances. 029 * 030 * @author Sam Brannen 031 * @author Juergen Hoeller 032 * @since 2.5 033 */ 034public class DependencyInjectionTestExecutionListener extends AbstractTestExecutionListener { 035 036 /** 037 * Attribute name for a {@link TestContext} attribute which indicates 038 * whether or not the dependencies of a test instance should be 039 * <em>reinjected</em> in 040 * {@link #beforeTestMethod(TestContext) beforeTestMethod()}. Note that 041 * dependencies will be injected in 042 * {@link #prepareTestInstance(TestContext) prepareTestInstance()} in any 043 * case. 044 * <p>Clients of a {@link TestContext} (e.g., other 045 * {@link org.springframework.test.context.TestExecutionListener TestExecutionListeners}) 046 * may therefore choose to set this attribute to signal that dependencies 047 * should be reinjected <em>between</em> execution of individual test 048 * methods. 049 * <p>Permissible values include {@link Boolean#TRUE} and {@link Boolean#FALSE}. 050 */ 051 public static final String REINJECT_DEPENDENCIES_ATTRIBUTE = Conventions.getQualifiedAttributeName( 052 DependencyInjectionTestExecutionListener.class, "reinjectDependencies"); 053 054 private static final Log logger = LogFactory.getLog(DependencyInjectionTestExecutionListener.class); 055 056 057 /** 058 * Returns {@code 2000}. 059 */ 060 @Override 061 public final int getOrder() { 062 return 2000; 063 } 064 065 /** 066 * Performs dependency injection on the 067 * {@link TestContext#getTestInstance() test instance} of the supplied 068 * {@link TestContext test context} by 069 * {@link AutowireCapableBeanFactory#autowireBeanProperties(Object, int, boolean) autowiring} 070 * and 071 * {@link AutowireCapableBeanFactory#initializeBean(Object, String) initializing} 072 * the test instance via its own 073 * {@link TestContext#getApplicationContext() application context} (without 074 * checking dependencies). 075 * <p>The {@link #REINJECT_DEPENDENCIES_ATTRIBUTE} will be subsequently removed 076 * from the test context, regardless of its value. 077 */ 078 @Override 079 public void prepareTestInstance(TestContext testContext) throws Exception { 080 if (logger.isDebugEnabled()) { 081 logger.debug("Performing dependency injection for test context [" + testContext + "]."); 082 } 083 injectDependencies(testContext); 084 } 085 086 /** 087 * If the {@link #REINJECT_DEPENDENCIES_ATTRIBUTE} in the supplied 088 * {@link TestContext test context} has a value of {@link Boolean#TRUE}, 089 * this method will have the same effect as 090 * {@link #prepareTestInstance(TestContext) prepareTestInstance()}; 091 * otherwise, this method will have no effect. 092 */ 093 @Override 094 public void beforeTestMethod(TestContext testContext) throws Exception { 095 if (Boolean.TRUE.equals(testContext.getAttribute(REINJECT_DEPENDENCIES_ATTRIBUTE))) { 096 if (logger.isDebugEnabled()) { 097 logger.debug("Reinjecting dependencies for test context [" + testContext + "]."); 098 } 099 injectDependencies(testContext); 100 } 101 } 102 103 /** 104 * Performs dependency injection and bean initialization for the supplied 105 * {@link TestContext} as described in 106 * {@link #prepareTestInstance(TestContext) prepareTestInstance()}. 107 * <p>The {@link #REINJECT_DEPENDENCIES_ATTRIBUTE} will be subsequently removed 108 * from the test context, regardless of its value. 109 * @param testContext the test context for which dependency injection should 110 * be performed (never {@code null}) 111 * @throws Exception allows any exception to propagate 112 * @see #prepareTestInstance(TestContext) 113 * @see #beforeTestMethod(TestContext) 114 */ 115 protected void injectDependencies(TestContext testContext) throws Exception { 116 Object bean = testContext.getTestInstance(); 117 AutowireCapableBeanFactory beanFactory = testContext.getApplicationContext().getAutowireCapableBeanFactory(); 118 beanFactory.autowireBeanProperties(bean, AutowireCapableBeanFactory.AUTOWIRE_NO, false); 119 beanFactory.initializeBean(bean, testContext.getTestClass().getName()); 120 testContext.removeAttribute(REINJECT_DEPENDENCIES_ATTRIBUTE); 121 } 122 123}