Skip to content

Commit 3da5fbe

Browse files
committed
Introduce before/after test execution support in AbstractTestNGSpringContextTests
Issue: SPR-4365
1 parent 087efa6 commit 3da5fbe

File tree

2 files changed

+107
-69
lines changed

2 files changed

+107
-69
lines changed

spring-test/src/main/java/org/springframework/test/context/testng/AbstractTestNGSpringContextTests.java

Lines changed: 47 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2014 the original author or authors.
2+
* Copyright 2002-2016 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -49,12 +49,11 @@
4949
* <p>Concrete subclasses:
5050
* <ul>
5151
* <li>Typically declare a class-level {@link ContextConfiguration
52-
* &#064;ContextConfiguration} annotation to configure the {@link ApplicationContext
53-
* application context} {@link ContextConfiguration#locations() resource locations}
54-
* or {@link ContextConfiguration#classes() annotated classes}. <em>If your test
52+
* &#064;ContextConfiguration} annotation to configure the {@linkplain ApplicationContext
53+
* application context} {@linkplain ContextConfiguration#locations() resource locations}
54+
* or {@linkplain ContextConfiguration#classes() annotated classes}. <em>If your test
5555
* does not need to load an application context, you may choose to omit the
56-
* {@link ContextConfiguration &#064;ContextConfiguration} declaration and to
57-
* configure the appropriate
56+
* {@code @ContextConfiguration} declaration and to configure the appropriate
5857
* {@link org.springframework.test.context.TestExecutionListener TestExecutionListeners}
5958
* manually.</em></li>
6059
* <li>Must have constructors which either implicitly or explicitly delegate to
@@ -105,7 +104,7 @@ public abstract class AbstractTestNGSpringContextTests implements IHookable, App
105104

106105
/**
107106
* Construct a new AbstractTestNGSpringContextTests instance and initialize
108-
* the internal {@link TestContextManager} for the current test.
107+
* the internal {@link TestContextManager} for the current test class.
109108
*/
110109
public AbstractTestNGSpringContextTests() {
111110
this.testContextManager = new TestContextManager(getClass());
@@ -124,7 +123,7 @@ public final void setApplicationContext(ApplicationContext applicationContext) {
124123

125124
/**
126125
* Delegates to the configured {@link TestContextManager} to call
127-
* {@link TestContextManager#beforeTestClass() 'before test class'}
126+
* {@linkplain TestContextManager#beforeTestClass() 'before test class'}
128127
* callbacks.
129128
*
130129
* @throws Exception if a registered TestExecutionListener throws an
@@ -137,7 +136,7 @@ protected void springTestContextBeforeTestClass() throws Exception {
137136

138137
/**
139138
* Delegates to the configured {@link TestContextManager} to
140-
* {@link TestContextManager#prepareTestInstance(Object) prepare} this test
139+
* {@linkplain TestContextManager#prepareTestInstance(Object) prepare} this test
141140
* instance prior to execution of any individual tests, for example for
142141
* injecting dependencies, etc.
143142
*
@@ -151,39 +150,57 @@ protected void springTestContextPrepareTestInstance() throws Exception {
151150

152151
/**
153152
* Delegates to the configured {@link TestContextManager} to
154-
* {@link TestContextManager#beforeTestMethod(Object,Method) pre-process}
153+
* {@linkplain TestContextManager#beforeTestMethod(Object,Method) pre-process}
155154
* the test method before the actual test is executed.
156155
*
157-
* @param testMethod the test method which is about to be executed.
158-
* @throws Exception allows all exceptions to propagate.
156+
* @param testMethod the test method which is about to be executed
157+
* @throws Exception allows all exceptions to propagate
159158
*/
160159
@BeforeMethod(alwaysRun = true)
161160
protected void springTestContextBeforeTestMethod(Method testMethod) throws Exception {
162161
this.testContextManager.beforeTestMethod(this, testMethod);
163162
}
164163

165164
/**
166-
* Delegates to the {@link IHookCallBack#runTestMethod(ITestResult) test
165+
* Delegates to the {@linkplain IHookCallBack#runTestMethod(ITestResult) test
167166
* method} in the supplied {@code callback} to execute the actual test
168167
* and then tracks the exception thrown during test execution, if any.
169168
*
170-
* @see org.testng.IHookable#run(org.testng.IHookCallBack,
171-
* org.testng.ITestResult)
169+
* @see org.testng.IHookable#run(IHookCallBack, ITestResult)
172170
*/
173171
@Override
174172
public void run(IHookCallBack callBack, ITestResult testResult) {
175-
callBack.runTestMethod(testResult);
173+
Method testMethod = testResult.getMethod().getConstructorOrMethod().getMethod();
174+
boolean beforeCallbacksExecuted = false;
176175

177-
Throwable testResultException = testResult.getThrowable();
178-
if (testResultException instanceof InvocationTargetException) {
179-
testResultException = ((InvocationTargetException) testResultException).getCause();
176+
try {
177+
this.testContextManager.beforeTestExecution(this, testMethod);
178+
beforeCallbacksExecuted = true;
179+
}
180+
catch (Throwable ex) {
181+
testResult.setThrowable(ex);
182+
this.testException = ex;
183+
}
184+
185+
if (beforeCallbacksExecuted) {
186+
callBack.runTestMethod(testResult);
187+
this.testException = getTestResultException(testResult);
188+
}
189+
190+
try {
191+
this.testContextManager.afterTestExecution(this, testMethod, this.testException);
192+
}
193+
catch (Throwable ex) {
194+
if (this.testException == null) {
195+
testResult.setThrowable(ex);
196+
this.testException = ex;
197+
}
180198
}
181-
this.testException = testResultException;
182199
}
183200

184201
/**
185202
* Delegates to the configured {@link TestContextManager} to
186-
* {@link TestContextManager#afterTestMethod(Object, Method, Throwable)
203+
* {@linkplain TestContextManager#afterTestMethod(Object, Method, Throwable)
187204
* post-process} the test method after the actual test has executed.
188205
*
189206
* @param testMethod the test method which has just been executed on the
@@ -202,7 +219,7 @@ protected void springTestContextAfterTestMethod(Method testMethod) throws Except
202219

203220
/**
204221
* Delegates to the configured {@link TestContextManager} to call
205-
* {@link TestContextManager#afterTestClass() 'after test class'} callbacks.
222+
* {@linkplain TestContextManager#afterTestClass() 'after test class'} callbacks.
206223
*
207224
* @throws Exception if a registered TestExecutionListener throws an
208225
* exception
@@ -212,4 +229,12 @@ protected void springTestContextAfterTestClass() throws Exception {
212229
this.testContextManager.afterTestClass();
213230
}
214231

232+
private Throwable getTestResultException(ITestResult testResult) {
233+
Throwable testResultException = testResult.getThrowable();
234+
if (testResultException instanceof InvocationTargetException) {
235+
testResultException = ((InvocationTargetException) testResultException).getCause();
236+
}
237+
return testResultException;
238+
}
239+
215240
}

spring-test/src/test/java/org/springframework/test/context/junit4/FailingBeforeAndAfterMethodsTestNGTests.java

Lines changed: 60 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2015 the original author or authors.
2+
* Copyright 2002-2016 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -16,9 +16,6 @@
1616

1717
package org.springframework.test.context.junit4;
1818

19-
import java.util.Arrays;
20-
import java.util.Collection;
21-
2219
import org.junit.Test;
2320
import org.junit.runner.RunWith;
2421
import org.junit.runners.Parameterized;
@@ -28,7 +25,6 @@
2825
import org.springframework.test.context.TestContext;
2926
import org.springframework.test.context.TestExecutionListener;
3027
import org.springframework.test.context.TestExecutionListeners;
31-
import org.springframework.test.context.support.AbstractTestExecutionListener;
3228
import org.springframework.test.context.testng.AbstractTestNGSpringContextTests;
3329
import org.springframework.test.context.testng.AbstractTransactionalTestNGSpringContextTests;
3430
import org.springframework.test.context.testng.TrackingTestNGTestListener;
@@ -41,25 +37,15 @@
4137
import static org.junit.Assert.*;
4238

4339
/**
44-
* <p>
45-
* JUnit 4 based integration test for verifying that '<i>before</i>' and '<i>after</i>'
40+
* Integration tests which verify that '<i>before</i>' and '<i>after</i>'
4641
* methods of {@link TestExecutionListener TestExecutionListeners} as well as
47-
* {@link BeforeTransaction &#064;BeforeTransaction} and
48-
* {@link AfterTransaction &#064;AfterTransaction} methods can fail a test in a
49-
* TestNG environment, as requested in <a
50-
* href="http://opensource.atlassian.com/projects/spring/browse/SPR-3960"
51-
* target="_blank">SPR-3960</a>.
52-
* </p>
53-
* <p>
54-
* Indirectly, this class also verifies that all {@link TestExecutionListener}
42+
* {@code @BeforeTransaction} and {@code @AfterTransaction} methods can fail
43+
* tests in a TestNG environment.
44+
*
45+
* <p>See: <a href="https://jira.spring.io/browse/SPR-3960" target="_blank">SPR-3960</a>.
46+
*
47+
* <p>Indirectly, this class also verifies that all {@code TestExecutionListener}
5548
* lifecycle callbacks are called.
56-
* </p>
57-
* <p>
58-
* As of Spring 3.0, this class also tests support for the new
59-
* {@link TestExecutionListener#beforeTestClass(TestContext) beforeTestClass()}
60-
* and {@link TestExecutionListener#afterTestClass(TestContext)
61-
* afterTestClass()} lifecycle callback methods.
62-
* </p>
6349
*
6450
* @author Sam Brannen
6551
* @since 2.5
@@ -75,17 +61,20 @@ public class FailingBeforeAndAfterMethodsTestNGTests {
7561

7662

7763
@Parameters(name = "{0}")
78-
public static Collection<Object[]> testData() {
79-
return Arrays.asList(new Object[][] {//
80-
//
81-
{ AlwaysFailingBeforeTestClassTestCase.class.getSimpleName(), 1, 0, 0, 1 },//
82-
{ AlwaysFailingAfterTestClassTestCase.class.getSimpleName(), 1, 1, 0, 1 },//
83-
{ AlwaysFailingPrepareTestInstanceTestCase.class.getSimpleName(), 1, 0, 0, 1 },//
84-
{ AlwaysFailingBeforeTestMethodTestCase.class.getSimpleName(), 1, 0, 0, 1 },//
85-
{ AlwaysFailingAfterTestMethodTestCase.class.getSimpleName(), 1, 1, 0, 1 },//
86-
{ FailingBeforeTransactionTestCase.class.getSimpleName(), 1, 0, 0, 1 },//
87-
{ FailingAfterTransactionTestCase.class.getSimpleName(), 1, 1, 0, 1 } //
88-
});
64+
public static Object[][] testData() {
65+
// @formatter:off
66+
return new Object[][] {
67+
{ AlwaysFailingBeforeTestClassTestCase.class.getSimpleName(), 1, 0, 0, 1 },
68+
{ AlwaysFailingAfterTestClassTestCase.class.getSimpleName(), 1, 1, 0, 1 },
69+
{ AlwaysFailingPrepareTestInstanceTestCase.class.getSimpleName(), 1, 0, 0, 1 },
70+
{ AlwaysFailingBeforeTestMethodTestCase.class.getSimpleName(), 1, 0, 0, 1 },
71+
{ AlwaysFailingBeforeTestExecutionTestCase.class.getSimpleName(), 1, 0, 1, 0 },
72+
{ AlwaysFailingAfterTestExecutionTestCase.class.getSimpleName(), 1, 0, 1, 0 },
73+
{ AlwaysFailingAfterTestMethodTestCase.class.getSimpleName(), 1, 1, 0, 1 },
74+
{ FailingBeforeTransactionTestCase.class.getSimpleName(), 1, 0, 0, 1 },
75+
{ FailingAfterTransactionTestCase.class.getSimpleName(), 1, 1, 0, 1 }
76+
};
77+
// @formatter:on
8978
}
9079

9180
public FailingBeforeAndAfterMethodsTestNGTests(String testClassName, int expectedTestStartCount,
@@ -106,51 +95,67 @@ public void runTestAndAssertCounters() throws Exception {
10695
testNG.setVerbose(0);
10796
testNG.run();
10897

109-
assertEquals("Verifying number of test starts for test class [" + this.clazz + "].",
110-
this.expectedTestStartCount, listener.testStartCount);
111-
assertEquals("Verifying number of successful tests for test class [" + this.clazz + "].",
112-
this.expectedTestSuccessCount, listener.testSuccessCount);
113-
assertEquals("Verifying number of failures for test class [" + this.clazz + "].", this.expectedFailureCount,
114-
listener.testFailureCount);
115-
assertEquals("Verifying number of failed configurations for test class [" + this.clazz + "].",
116-
this.expectedFailedConfigurationsCount, listener.failedConfigurationsCount);
98+
String name = this.clazz.getSimpleName();
99+
100+
assertEquals("tests started for [" + name + "] ==> ", this.expectedTestStartCount, listener.testStartCount);
101+
assertEquals("successful tests for [" + name + "] ==> ", this.expectedTestSuccessCount,
102+
listener.testSuccessCount);
103+
assertEquals("failed tests for [" + name + "] ==> ", this.expectedFailureCount, listener.testFailureCount);
104+
assertEquals("failed configurations for [" + name + "] ==> ", this.expectedFailedConfigurationsCount,
105+
listener.failedConfigurationsCount);
117106
}
118107

119108
// -------------------------------------------------------------------
120109

121-
static class AlwaysFailingBeforeTestClassTestExecutionListener extends AbstractTestExecutionListener {
110+
static class AlwaysFailingBeforeTestClassTestExecutionListener implements TestExecutionListener {
122111

123112
@Override
124113
public void beforeTestClass(TestContext testContext) {
125114
org.testng.Assert.fail("always failing beforeTestClass()");
126115
}
127116
}
128117

129-
static class AlwaysFailingAfterTestClassTestExecutionListener extends AbstractTestExecutionListener {
118+
static class AlwaysFailingAfterTestClassTestExecutionListener implements TestExecutionListener {
130119

131120
@Override
132121
public void afterTestClass(TestContext testContext) {
133122
org.testng.Assert.fail("always failing afterTestClass()");
134123
}
135124
}
136125

137-
static class AlwaysFailingPrepareTestInstanceTestExecutionListener extends AbstractTestExecutionListener {
126+
static class AlwaysFailingPrepareTestInstanceTestExecutionListener implements TestExecutionListener {
138127

139128
@Override
140129
public void prepareTestInstance(TestContext testContext) throws Exception {
141130
org.testng.Assert.fail("always failing prepareTestInstance()");
142131
}
143132
}
144133

145-
static class AlwaysFailingBeforeTestMethodTestExecutionListener extends AbstractTestExecutionListener {
134+
static class AlwaysFailingBeforeTestMethodTestExecutionListener implements TestExecutionListener {
146135

147136
@Override
148137
public void beforeTestMethod(TestContext testContext) {
149138
org.testng.Assert.fail("always failing beforeTestMethod()");
150139
}
151140
}
152141

153-
static class AlwaysFailingAfterTestMethodTestExecutionListener extends AbstractTestExecutionListener {
142+
static class AlwaysFailingBeforeTestExecutionTestExecutionListener implements TestExecutionListener {
143+
144+
@Override
145+
public void beforeTestExecution(TestContext testContext) {
146+
org.testng.Assert.fail("always failing beforeTestExecution()");
147+
}
148+
}
149+
150+
static class AlwaysFailingAfterTestExecutionTestExecutionListener implements TestExecutionListener {
151+
152+
@Override
153+
public void afterTestExecution(TestContext testContext) {
154+
org.testng.Assert.fail("always failing afterTestExecution()");
155+
}
156+
}
157+
158+
static class AlwaysFailingAfterTestMethodTestExecutionListener implements TestExecutionListener {
154159

155160
@Override
156161
public void afterTestMethod(TestContext testContext) {
@@ -160,7 +165,7 @@ public void afterTestMethod(TestContext testContext) {
160165

161166
// -------------------------------------------------------------------
162167

163-
@TestExecutionListeners(value = {}, inheritListeners = false)
168+
@TestExecutionListeners(inheritListeners = false)
164169
public static abstract class BaseTestCase extends AbstractTestNGSpringContextTests {
165170

166171
@org.testng.annotations.Test
@@ -184,6 +189,14 @@ public static class AlwaysFailingPrepareTestInstanceTestCase extends BaseTestCas
184189
public static class AlwaysFailingBeforeTestMethodTestCase extends BaseTestCase {
185190
}
186191

192+
@TestExecutionListeners(AlwaysFailingBeforeTestExecutionTestExecutionListener.class)
193+
public static class AlwaysFailingBeforeTestExecutionTestCase extends BaseTestCase {
194+
}
195+
196+
@TestExecutionListeners(AlwaysFailingAfterTestExecutionTestExecutionListener.class)
197+
public static class AlwaysFailingAfterTestExecutionTestCase extends BaseTestCase {
198+
}
199+
187200
@TestExecutionListeners(AlwaysFailingAfterTestMethodTestExecutionListener.class)
188201
public static class AlwaysFailingAfterTestMethodTestCase extends BaseTestCase {
189202
}

0 commit comments

Comments
 (0)