/* * Copyright 2002-2008 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.test.context.junit4; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.List; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.junit.After; import org.junit.Before; import org.junit.Ignore; import org.junit.Test; import org.junit.Test.None; import org.junit.internal.runners.TestClass; import org.springframework.test.annotation.ExpectedException; import org.springframework.test.annotation.ProfileValueSource; import org.springframework.test.annotation.ProfileValueUtils; /** * SpringTestMethod is a custom implementation of JUnit 4.4's * {@link org.junit.internal.runners.TestMethod TestMethod}. Due to method and * field visibility constraints, the code of TestMethod has been duplicated here * instead of subclassing TestMethod directly. * * <p>SpringTestMethod also provides support for * {@link org.springframework.test.annotation.IfProfileValue @IfProfileValue} * and {@link ExpectedException @ExpectedException}. See {@link #isIgnored()} * and {@link #getExpectedException()} for further details. * * @author Sam Brannen * @since 2.5 */ class SpringTestMethod { private static final Log logger = LogFactory.getLog(SpringTestMethod.class); private final Method method; private final TestClass testClass; /** * Constructs a test method for the supplied {@link Method method} and * {@link TestClass test class}; and retrieves the configured (or default) * {@link ProfileValueSource}. * @param method The test method * @param testClass the test class */ public SpringTestMethod(Method method, TestClass testClass) { this.method = method; this.testClass = testClass; } /** * Determine if this test method is {@link Test#expected() expected} to * throw an exception. */ public boolean expectsException() { return (getExpectedException() != null); } /** * Get the {@link After @After} methods for this test method. */ public List<Method> getAfters() { return getTestClass().getAnnotatedMethods(After.class); } /** * Get the {@link Before @Before} methods for this test method. */ public List<Method> getBefores() { return getTestClass().getAnnotatedMethods(Before.class); } /** * Get the <code>exception</code> that this test method is expected to throw. * <p>Supports both Spring's {@link ExpectedException @ExpectedException(...)} * and JUnit's {@link Test#expected() @Test(expected=...)} annotations, but * not both simultaneously. * @return the expected exception, or <code>null</code> if none was specified */ public Class<? extends Throwable> getExpectedException() throws IllegalStateException { ExpectedException expectedExAnn = getMethod().getAnnotation(ExpectedException.class); Test testAnnotation = getMethod().getAnnotation(Test.class); Class<? extends Throwable> expectedException = null; Class<? extends Throwable> springExpectedException = (expectedExAnn != null && expectedExAnn.value() != null ? expectedExAnn.value() : null); Class<? extends Throwable> junitExpectedException = (testAnnotation != null && testAnnotation.expected() != None.class ? testAnnotation.expected() : null); if (springExpectedException != null && junitExpectedException != null) { String msg = "Test method [" + getMethod() + "] has been configured with Spring's @ExpectedException(" + springExpectedException.getName() + ".class) and JUnit's @Test(expected=" + junitExpectedException.getName() + ".class) annotations. " + "Only one declaration of an 'expected exception' is permitted per test method."; logger.error(msg); throw new IllegalStateException(msg); } else if (springExpectedException != null) { expectedException = springExpectedException; } else if (junitExpectedException != null) { expectedException = junitExpectedException; } return expectedException; } /** * Get the actual {@link Method method} referenced by this test method. */ public final Method getMethod() { return this.method; } /** * Get the {@link TestClass test class} for this test method. */ public final TestClass getTestClass() { return this.testClass; } /** * Get the configured <code>timeout</code> for this test method. * <p>Supports JUnit's {@link Test#timeout() @Test(timeout=...)} annotation. * @return the timeout, or <code>0</code> if none was specified */ public long getTimeout() { Test testAnnotation = getMethod().getAnnotation(Test.class); return (testAnnotation != null && testAnnotation.timeout() > 0 ? testAnnotation.timeout() : 0); } /** * Convenience method for {@link Method#invoke(Object,Object...) invoking} * the method associated with this test method. Throws exceptions consistent * with {@link Method#invoke(Object,Object...) Method.invoke()}. * @param testInstance the test instance upon which to invoke the method */ public void invoke(Object testInstance) throws IllegalAccessException, InvocationTargetException { getMethod().invoke(testInstance); } /** * Determine if this test method should be ignored. * @return <code>true</code> if this test method should be ignored * @see ProfileValueUtils#isTestEnabledInThisEnvironment */ public boolean isIgnored() { return (getMethod().isAnnotationPresent(Ignore.class) || !ProfileValueUtils.isTestEnabledInThisEnvironment(this.method, this.testClass.getJavaClass())); } /** * Determine if this test method {@link Test#expected() expects} exceptions * of the type of the supplied <code>exception</code> to be thrown. * @param exception the thrown exception * @return <code>true</code> if the supplied exception was of an expected type */ public boolean isUnexpected(Throwable exception) { return !getExpectedException().isAssignableFrom(exception.getClass()); } }