001/*
002 * Copyright 2002-2015 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 java.lang.reflect.Method;
020
021import org.springframework.context.ApplicationContext;
022import org.springframework.context.ConfigurableApplicationContext;
023import org.springframework.core.AttributeAccessorSupport;
024import org.springframework.core.style.ToStringCreator;
025import org.springframework.test.annotation.DirtiesContext.HierarchyMode;
026import org.springframework.test.context.CacheAwareContextLoaderDelegate;
027import org.springframework.test.context.MergedContextConfiguration;
028import org.springframework.test.context.TestContext;
029import org.springframework.util.Assert;
030
031/**
032 * Default implementation of the {@link TestContext} interface.
033 *
034 * @author Sam Brannen
035 * @author Juergen Hoeller
036 * @since 4.0
037 */
038public class DefaultTestContext extends AttributeAccessorSupport implements TestContext {
039
040        private static final long serialVersionUID = -5827157174866681233L;
041
042        private final CacheAwareContextLoaderDelegate cacheAwareContextLoaderDelegate;
043
044        private final MergedContextConfiguration mergedContextConfiguration;
045
046        private final Class<?> testClass;
047
048        private Object testInstance;
049
050        private Method testMethod;
051
052        private Throwable testException;
053
054
055        /**
056         * Construct a new {@code DefaultTestContext} from the supplied arguments.
057         * @param testClass the test class for this test context; never {@code null}
058         * @param mergedContextConfiguration the merged application context
059         * configuration for this test context; never {@code null}
060         * @param cacheAwareContextLoaderDelegate the delegate to use for loading
061         * and closing the application context for this test context; never {@code null}
062         */
063        public DefaultTestContext(Class<?> testClass, MergedContextConfiguration mergedContextConfiguration,
064                        CacheAwareContextLoaderDelegate cacheAwareContextLoaderDelegate) {
065                Assert.notNull(testClass, "testClass must not be null");
066                Assert.notNull(mergedContextConfiguration, "MergedContextConfiguration must not be null");
067                Assert.notNull(cacheAwareContextLoaderDelegate, "CacheAwareContextLoaderDelegate must not be null");
068                this.testClass = testClass;
069                this.mergedContextConfiguration = mergedContextConfiguration;
070                this.cacheAwareContextLoaderDelegate = cacheAwareContextLoaderDelegate;
071        }
072
073        /**
074         * Get the {@linkplain ApplicationContext application context} for this
075         * test context.
076         * <p>The default implementation delegates to the {@link CacheAwareContextLoaderDelegate}
077         * that was supplied when this {@code TestContext} was constructed.
078         * @see CacheAwareContextLoaderDelegate#loadContext
079         * @throws IllegalStateException if the context returned by the context
080         * loader delegate is not <em>active</em> (i.e., has been closed).
081         */
082        public ApplicationContext getApplicationContext() {
083                ApplicationContext context = this.cacheAwareContextLoaderDelegate.loadContext(this.mergedContextConfiguration);
084                if (context instanceof ConfigurableApplicationContext) {
085                        @SuppressWarnings("resource")
086                        ConfigurableApplicationContext cac = (ConfigurableApplicationContext) context;
087                        Assert.state(cac.isActive(), "The ApplicationContext loaded for [" + mergedContextConfiguration
088                                        + "] is not active. Ensure that the context has not been closed programmatically.");
089                }
090                return context;
091        }
092
093        /**
094         * Mark the {@linkplain ApplicationContext application context} associated
095         * with this test context as <em>dirty</em> (i.e., by removing it from the
096         * context cache and closing it).
097         * <p>The default implementation delegates to the {@link CacheAwareContextLoaderDelegate}
098         * that was supplied when this {@code TestContext} was constructed.
099         * @see CacheAwareContextLoaderDelegate#closeContext
100         */
101        public void markApplicationContextDirty(HierarchyMode hierarchyMode) {
102                this.cacheAwareContextLoaderDelegate.closeContext(this.mergedContextConfiguration, hierarchyMode);
103        }
104
105        public final Class<?> getTestClass() {
106                return this.testClass;
107        }
108
109        public final Object getTestInstance() {
110                return this.testInstance;
111        }
112
113        public final Method getTestMethod() {
114                return this.testMethod;
115        }
116
117        public final Throwable getTestException() {
118                return this.testException;
119        }
120
121        public void updateState(Object testInstance, Method testMethod, Throwable testException) {
122                this.testInstance = testInstance;
123                this.testMethod = testMethod;
124                this.testException = testException;
125        }
126
127
128        /**
129         * Provide a String representation of this test context's state.
130         */
131        @Override
132        public String toString() {
133                return new ToStringCreator(this)
134                                .append("testClass", this.testClass)
135                                .append("testInstance", this.testInstance)
136                                .append("testMethod", this.testMethod)
137                                .append("testException", this.testException)
138                                .append("mergedContextConfiguration", this.mergedContextConfiguration)
139                                .toString();
140        }
141
142}