[SPR-5145] Improved test suite for SpringJUnit4ClassRunner: added specific unit tests for test timeouts, repeated tests, and expected exceptions.

This commit is contained in:
Sam Brannen 2009-04-29 21:29:53 +00:00
parent 41423a9ab9
commit 6327b3484b
6 changed files with 454 additions and 94 deletions

View File

@ -0,0 +1,87 @@
/*
* Copyright 2002-2009 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 static org.junit.Assert.assertEquals;
import java.util.ArrayList;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runner.notification.RunNotifier;
import org.junit.runners.JUnit4;
import org.springframework.test.annotation.ExpectedException;
import org.springframework.test.context.TestExecutionListeners;
/**
* Verifies proper handling of the following in conjunction with the
* {@link SpringJUnit4ClassRunner}:
* <ul>
* <li>JUnit's {@link Test#expected() &#064;Test(expected=...)}</li>
* <li>Spring's {@link ExpectedException &#064;ExpectedException}</li>
* </ul>
*
* @author Sam Brannen
* @since 3.0
*/
@RunWith(JUnit4.class)
public class ExpectedExceptionSpringRunnerTests {
@Test
public void timedTests() throws Exception {
Class<ExpectedExceptionSpringRunnerTestCase> testClass = ExpectedExceptionSpringRunnerTestCase.class;
TrackingRunListener listener = new TrackingRunListener();
RunNotifier notifier = new RunNotifier();
notifier.addListener(listener);
new SpringJUnit4ClassRunner(testClass).run(notifier);
assertEquals("Verifying number of failures for test class [" + testClass + "].", 1,
listener.getTestFailureCount());
assertEquals("Verifying number of tests started for test class [" + testClass + "].", 3,
listener.getTestStartedCount());
assertEquals("Verifying number of tests finished for test class [" + testClass + "].", 3,
listener.getTestFinishedCount());
}
@RunWith(SpringJUnit4ClassRunner.class)
@TestExecutionListeners( {})
public static final class ExpectedExceptionSpringRunnerTestCase {
// Should Pass.
@Test(expected = IndexOutOfBoundsException.class)
public void verifyJUnitExpectedException() {
new ArrayList<Object>().get(1);
}
// Should Pass.
@Test
@ExpectedException(IndexOutOfBoundsException.class)
public void verifySpringExpectedException() {
new ArrayList<Object>().get(1);
}
// Should Fail due to duplicate configuration.
@Test(expected = IllegalStateException.class)
@ExpectedException(IllegalStateException.class)
public void verifyJUnitAndSpringExpectedException() {
new ArrayList<Object>().get(1);
}
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2002-2007 the original author or authors.
* Copyright 2002-2009 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.
@ -17,18 +17,16 @@
package org.springframework.test.context.junit4;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail;
import java.util.Arrays;
import java.util.Collection;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runner.notification.Failure;
import org.junit.runner.notification.RunListener;
import org.junit.runner.notification.RunNotifier;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameters;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.TestContext;
import org.springframework.test.context.TestExecutionListener;
@ -39,15 +37,15 @@ import org.springframework.test.context.transaction.BeforeTransaction;
/**
* <p>
* JUnit 4 based unit test for verifying that '<em>before</em>' and '<em>after</em>'
* methods of {@link TestExecutionListener TestExecutionListeners} as well as
* {@link BeforeTransaction @BeforeTransaction} and
* {@link AfterTransaction @AfterTransaction} methods can fail a test in a JUnit
* 4.4 environment, as requested in <a
* JUnit 4 based unit test for verifying that '<em>before</em>' and '
* <em>after</em>' methods of {@link TestExecutionListener
* TestExecutionListeners} as well as {@link BeforeTransaction
* &#064;BeforeTransaction} and {@link AfterTransaction &#064;AfterTransaction}
* methods can fail a test in a JUnit 4.4 environment, as requested in <a
* href="http://opensource.atlassian.com/projects/spring/browse/SPR-3960"
* target="_blank">SPR-3960</a>.
* </p>
*
*
* @author Sam Brannen
* @since 2.5
*/
@ -63,39 +61,23 @@ public class FailingBeforeAndAfterMethodsTests {
@Parameters
public static Collection<Object[]> testData() {
return Arrays.asList(new Object[][] {
{ AlwaysFailingBeforeTestMethodTestCase.class },
{ AlwaysFailingAfterTestMethodTestCase.class },
{ FailingBeforeTransactionalTestCase.class },
{ FailingAfterTransactionalTestCase.class }
return Arrays.asList(new Object[][] {//
//
{ AlwaysFailingBeforeTestMethodTestCase.class },//
{ AlwaysFailingAfterTestMethodTestCase.class },//
{ FailingBeforeTransactionalTestCase.class },//
{ FailingAfterTransactionalTestCase.class } //
});
}
@Test
public void runTestAndAssertCounters() throws Exception {
final FailureTrackingRunListener failureTrackingRunListener = new FailureTrackingRunListener();
final TrackingRunListener listener = new TrackingRunListener();
final RunNotifier notifier = new RunNotifier();
notifier.addListener(failureTrackingRunListener);
notifier.addListener(listener);
new SpringJUnit4ClassRunner(this.clazz).run(notifier);
assertEquals("Verifying number of failures for test class [" + this.clazz + "].", 1,
failureTrackingRunListener.failureCount);
}
static class FailureTrackingRunListener extends RunListener {
int failureCount = 0;
public void testFailure(Failure failure) throws Exception {
this.failureCount++;
}
assertEquals("Verifying number of failures for test class [" + this.clazz + "].", 1, listener.getTestFailureCount());
}
@ -103,20 +85,18 @@ public class FailingBeforeAndAfterMethodsTests {
@Override
public void beforeTestMethod(TestContext testContext) {
org.junit.Assert.fail("always failing beforeTestMethod()");
fail("always failing beforeTestMethod()");
}
}
static class AlwaysFailingAfterTestMethodTestExecutionListener extends AbstractTestExecutionListener {
@Override
public void afterTestMethod(TestContext testContext) {
org.junit.Assert.fail("always failing afterTestMethod()");
fail("always failing afterTestMethod()");
}
}
@TestExecutionListeners(value = { AlwaysFailingBeforeTestMethodTestExecutionListener.class }, inheritListeners = false)
public static class AlwaysFailingBeforeTestMethodTestCase extends AbstractJUnit4SpringContextTests {
@ -125,7 +105,6 @@ public class FailingBeforeAndAfterMethodsTests {
}
}
@TestExecutionListeners(value = { AlwaysFailingAfterTestMethodTestExecutionListener.class }, inheritListeners = false)
public static class AlwaysFailingAfterTestMethodTestCase extends AbstractJUnit4SpringContextTests {
@ -134,7 +113,6 @@ public class FailingBeforeAndAfterMethodsTests {
}
}
@ContextConfiguration(locations = { "FailingBeforeAndAfterMethodsTests-context.xml" })
public static class FailingBeforeTransactionalTestCase extends AbstractTransactionalJUnit4SpringContextTests {
@ -144,11 +122,10 @@ public class FailingBeforeAndAfterMethodsTests {
@BeforeTransaction
public void beforeTransaction() {
org.junit.Assert.fail("always failing beforeTransaction()");
fail("always failing beforeTransaction()");
}
}
@ContextConfiguration(locations = { "FailingBeforeAndAfterMethodsTests-context.xml" })
public static class FailingAfterTransactionalTestCase extends AbstractTransactionalJUnit4SpringContextTests {
@ -158,7 +135,7 @@ public class FailingBeforeAndAfterMethodsTests {
@AfterTransaction
public void afterTransaction() {
org.junit.Assert.fail("always failing afterTransaction()");
fail("always failing afterTransaction()");
}
}

View File

@ -0,0 +1,151 @@
/*
* Copyright 2002-2009 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 static org.junit.Assert.assertEquals;
import java.io.IOException;
import java.util.Arrays;
import java.util.Collection;
import java.util.concurrent.atomic.AtomicInteger;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runner.notification.RunNotifier;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameters;
import org.springframework.test.annotation.Repeat;
import org.springframework.test.annotation.Timed;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.TestExecutionListeners;
/**
* Verifies proper handling of the following in conjunction with the
* {@link SpringJUnit4ClassRunner}:
* <ul>
* <li>Spring's {@link Repeat &#064;Repeat}</li>
* <li>Spring's {@link Timed &#064;Timed}</li>
* </ul>
*
* @author Sam Brannen
* @since 3.0
*/
@RunWith(Parameterized.class)
public class RepeatedSpringRunnerTests {
private static final AtomicInteger invocationCount = new AtomicInteger();
private final Class<? extends AbstractRepeatedTestCase> testClass;
private final int expectedFailureCount;
private final int expectedTestStartedCount;
private final int expectedTestFinishedCount;
private final int expectedInvocationCount;
public RepeatedSpringRunnerTests(Class<? extends AbstractRepeatedTestCase> testClass, int expectedFailureCount,
int expectedTestStartedCount, int expectedTestFinishedCount, int expectedInvocationCount) {
this.testClass = testClass;
this.expectedFailureCount = expectedFailureCount;
this.expectedTestStartedCount = expectedTestStartedCount;
this.expectedTestFinishedCount = expectedTestFinishedCount;
this.expectedInvocationCount = expectedInvocationCount;
}
@Parameters
public static Collection<Object[]> repetitionData() {
return Arrays.asList(new Object[][] {//
//
{ NonAnnotatedRepeatedTestCase.class, 0, 1, 1, 1 },//
{ DefaultRepeatValueRepeatedTestCase.class, 0, 1, 1, 1 },//
{ NegativeRepeatValueRepeatedTestCase.class, 0, 1, 1, 1 },//
{ RepeatedFiveTimesRepeatedTestCase.class, 0, 1, 1, 5 } //
});
}
@Test
public void assertRepetitions() throws Exception {
TrackingRunListener listener = new TrackingRunListener();
RunNotifier notifier = new RunNotifier();
notifier.addListener(listener);
invocationCount.set(0);
new SpringJUnit4ClassRunner(this.testClass).run(notifier);
assertEquals("Verifying number of failures for test class [" + this.testClass + "].",
this.expectedFailureCount, listener.getTestFailureCount());
assertEquals("Verifying number of tests started for test class [" + this.testClass + "].",
this.expectedTestStartedCount, listener.getTestStartedCount());
assertEquals("Verifying number of tests finished for test class [" + this.testClass + "].",
this.expectedTestFinishedCount, listener.getTestFinishedCount());
assertEquals("Verifying number of invocations for test class [" + this.testClass + "].",
this.expectedInvocationCount, invocationCount.get());
}
@RunWith(SpringJUnit4ClassRunner.class)
@TestExecutionListeners( {})
@ContextConfiguration(locations = {})
public abstract static class AbstractRepeatedTestCase {
protected void incrementInvocationCount() throws IOException {
invocationCount.incrementAndGet();
}
}
public static final class NonAnnotatedRepeatedTestCase extends AbstractRepeatedTestCase {
@Test
@Timed(millis = 10000)
public void testNonAnnotated() throws Exception {
incrementInvocationCount();
}
}
public static final class DefaultRepeatValueRepeatedTestCase extends AbstractRepeatedTestCase {
@Test
@Repeat
@Timed(millis = 10000)
public void testDefaultRepeatValue() throws Exception {
incrementInvocationCount();
}
}
public static final class NegativeRepeatValueRepeatedTestCase extends AbstractRepeatedTestCase {
@Test
@Repeat(-5)
@Timed(millis = 10000)
public void testNegativeRepeatValue() throws Exception {
incrementInvocationCount();
}
}
public static final class RepeatedFiveTimesRepeatedTestCase extends AbstractRepeatedTestCase {
@Test
@Repeat(5)
@Timed(millis = 10000)
public void testRepeatedFiveTimes() throws Exception {
incrementInvocationCount();
}
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2002-2007 the original author or authors.
* Copyright 2002-2009 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.
@ -19,13 +19,12 @@ package org.springframework.test.context.junit4;
import org.junit.runner.RunWith;
import org.junit.runners.Suite;
import org.junit.runners.Suite.SuiteClasses;
import org.springframework.test.context.SpringRunnerContextCacheTests;
/**
* <p>
* JUnit 4 based test suite for tests involving {@link SpringJUnit4ClassRunner},
* {@link SpringMethodRoadie}, and Spring's annotation-based test support.
* JUnit 4 based test suite for tests involving {@link SpringJUnit4ClassRunner}
* and the <em>Spring TestContext Framework</em>.
* </p>
* <p>
* This test suite serves a dual purpose of verifying that tests run with
@ -37,57 +36,38 @@ import org.springframework.test.context.SpringRunnerContextCacheTests;
* from an automated build process, test runner, etc. that is configured to run
* tests based on a &quot;*Tests.class&quot; pattern match.
* </p>
*
*
* @author Sam Brannen
* @since 2.5
*/
@RunWith(Suite.class)
// Note: the following 'multi-line' layout is for enhanced code readability.
@SuiteClasses( {
StandardJUnit4FeaturesTests.class,
StandardJUnit4FeaturesSpringRunnerTests.class,
EnabledAndIgnoredSpringRunnerTests.class,
HardCodedProfileValueSourceSpringRunnerTests.class,
SpringJUnit4ClassRunnerAppCtxTests.class,
ClassPathResourceSpringJUnit4ClassRunnerAppCtxTests.class,
AbsolutePathSpringJUnit4ClassRunnerAppCtxTests.class,
RelativePathSpringJUnit4ClassRunnerAppCtxTests.class,
MultipleResourcesSpringJUnit4ClassRunnerAppCtxTests.class,
InheritedConfigSpringJUnit4ClassRunnerAppCtxTests.class,
PropertiesBasedSpringJUnit4ClassRunnerAppCtxTests.class,
SpringRunnerContextCacheTests.class,
ParameterizedDependencyInjectionTests.class,
ClassLevelTransactionalSpringRunnerTests.class,
MethodLevelTransactionalSpringRunnerTests.class,
DefaultRollbackTrueTransactionalSpringRunnerTests.class,
DefaultRollbackFalseTransactionalSpringRunnerTests.class,
RollbackOverrideDefaultRollbackTrueTransactionalSpringRunnerTests.class,
RollbackOverrideDefaultRollbackFalseTransactionalSpringRunnerTests.class,
BeforeAndAfterTransactionAnnotationTests.class,
TimedTransactionalSpringRunnerTests.class
@SuiteClasses( {//
StandardJUnit4FeaturesTests.class,//
StandardJUnit4FeaturesSpringRunnerTests.class,//
ExpectedExceptionSpringRunnerTests.class,//
TimedSpringRunnerTests.class,//
RepeatedSpringRunnerTests.class,//
EnabledAndIgnoredSpringRunnerTests.class,//
HardCodedProfileValueSourceSpringRunnerTests.class,//
SpringJUnit4ClassRunnerAppCtxTests.class,//
ClassPathResourceSpringJUnit4ClassRunnerAppCtxTests.class,//
AbsolutePathSpringJUnit4ClassRunnerAppCtxTests.class,//
RelativePathSpringJUnit4ClassRunnerAppCtxTests.class,//
MultipleResourcesSpringJUnit4ClassRunnerAppCtxTests.class,//
InheritedConfigSpringJUnit4ClassRunnerAppCtxTests.class,//
PropertiesBasedSpringJUnit4ClassRunnerAppCtxTests.class,//
SpringRunnerContextCacheTests.class,//
ParameterizedDependencyInjectionTests.class,//
ClassLevelTransactionalSpringRunnerTests.class,//
MethodLevelTransactionalSpringRunnerTests.class,//
DefaultRollbackTrueTransactionalSpringRunnerTests.class,//
DefaultRollbackFalseTransactionalSpringRunnerTests.class,//
RollbackOverrideDefaultRollbackTrueTransactionalSpringRunnerTests.class,//
RollbackOverrideDefaultRollbackFalseTransactionalSpringRunnerTests.class,//
BeforeAndAfterTransactionAnnotationTests.class,//
TimedTransactionalSpringRunnerTests.class //
})
public class SpringJUnit4SuiteTests {
/* this test case is comprised completely of tests loaded as a suite. */
/* this test case consists entirely of tests loaded as a suite. */
}

View File

@ -0,0 +1,97 @@
/*
* Copyright 2002-2009 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 static org.junit.Assert.assertEquals;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runner.notification.RunNotifier;
import org.junit.runners.JUnit4;
import org.springframework.test.annotation.Timed;
import org.springframework.test.context.TestExecutionListeners;
/**
* Verifies proper handling of the following in conjunction with the
* {@link SpringJUnit4ClassRunner}:
* <ul>
* <li>JUnit's {@link Test#timeout() @Test(timeout=...)}</li>
* <li>Spring's {@link Timed @Timed}</li>
* </ul>
*
* @author Sam Brannen
* @since 3.0
*/
@RunWith(JUnit4.class)
public class TimedSpringRunnerTests {
@Test
public void timedTests() throws Exception {
Class<TimedSpringRunnerTestCase> testClass = TimedSpringRunnerTestCase.class;
TrackingRunListener listener = new TrackingRunListener();
RunNotifier notifier = new RunNotifier();
notifier.addListener(listener);
new SpringJUnit4ClassRunner(testClass).run(notifier);
assertEquals("Verifying number of failures for test class [" + testClass + "].", 3,
listener.getTestFailureCount());
assertEquals("Verifying number of tests started for test class [" + testClass + "].", 5,
listener.getTestStartedCount());
assertEquals("Verifying number of tests finished for test class [" + testClass + "].", 5,
listener.getTestFinishedCount());
}
@RunWith(SpringJUnit4ClassRunner.class)
@TestExecutionListeners( {})
public static final class TimedSpringRunnerTestCase {
// Should Pass.
@Test(timeout = 2000)
public void testJUnitTimeoutWithNoOp() {
/* no-op */
}
// Should Pass.
@Test
@Timed(millis = 2000)
public void testSpringTimeoutWithNoOp() {
/* no-op */
}
// Should Fail due to timeout.
@Test(timeout = 200)
public void testJUnitTimeoutWithOneSecondWait() throws Exception {
Thread.sleep(1000);
}
// Should Fail due to timeout.
@Test
@Timed(millis = 200)
public void testSpringTimeoutWithOneSecondWait() throws Exception {
Thread.sleep(1000);
}
// Should Fail due to duplicate configuration.
@Test(timeout = 200)
@Timed(millis = 200)
public void testSpringAndJUnitTimeout() {
/* no-op */
}
}
}

View File

@ -0,0 +1,68 @@
/*
* Copyright 2002-2009 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.util.concurrent.atomic.AtomicInteger;
import org.junit.runner.Description;
import org.junit.runner.notification.Failure;
import org.junit.runner.notification.RunListener;
/**
* Simple {@link RunListener} which tracks how many times certain JUnit callback
* methods were called: only intended for the integration test suite.
*
* @author Sam Brannen
* @since 3.0
*/
public class TrackingRunListener extends RunListener {
private final AtomicInteger testFailureCount = new AtomicInteger();
private final AtomicInteger testStartedCount = new AtomicInteger();
private final AtomicInteger testFinishedCount = new AtomicInteger();
public int getTestFailureCount() {
return this.testFailureCount.get();
}
public int getTestStartedCount() {
return this.testStartedCount.get();
}
public int getTestFinishedCount() {
return this.testFinishedCount.get();
}
@Override
public void testFailure(Failure failure) throws Exception {
this.testFailureCount.incrementAndGet();
}
@Override
public void testStarted(Description description) throws Exception {
this.testStartedCount.incrementAndGet();
}
@Override
public void testFinished(Description description) throws Exception {
this.testFinishedCount.incrementAndGet();
}
}