Skip to content

Commit 1362601

Browse files
authored
Merge pull request #21 from Nordstrom/pr/use-runner-as-context
Pr/use runner as context
2 parents 11f72dd + 6200290 commit 1362601

File tree

4 files changed

+62
-14
lines changed

4 files changed

+62
-14
lines changed

README.md

Lines changed: 19 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -43,22 +43,28 @@ import com.nordstrom.automation.junit.AtomicTest;
4343
import com.nordstrom.automation.junit.LifecycleHooks;
4444
import com.nordstrom.automation.junit.MethodWatcher;
4545
import com.nordstrom.automation.junit.RunReflectiveCall;
46-
import com.nordstrom.automation.junit.TestClassWatcher;
46+
import com.nordstrom.automation.junit.TestClassWatcher2;
4747
import org.junit.runners.model.FrameworkMethod;
4848
import org.junit.runners.model.TestClass;
4949

50-
public class ExploringWatcher implements TestClassWatcher, MethodWatcher {
50+
public class ExploringWatcher implements TestClassWatcher2, MethodWatcher {
5151

5252
...
5353

5454
@Override
55-
public void testClassStarted(TestClass testClass) {
56-
// get the 'atomic test' for this runner
57-
AtomicTest atomicTest = RunReflectiveCall.getAtomicTestFor(testClass);
58-
// get the 'particle' methods of this 'atomic test'
59-
List<FrameworkMethod> particles = atomicTest.getParticles();
60-
// get the parent of this runner
61-
TestClass parent = LifecycleHooks.getParentOf(testClass);
55+
public void testClassStarted(TestClass testClass, Object runner) {
56+
// if this is a Suite runner
57+
if (runner instanceof org.junit.runners.Suite) {
58+
// get the parent of this runner
59+
Object parent = LifecycleHooks.getParentOf(runner);
60+
...
61+
} else {
62+
// get the 'atomic test' for this runner
63+
AtomicTest atomicTest = RunReflectiveCall.getAtomicTestFor(testClass);
64+
// get the 'particle' methods of this 'atomic test'
65+
List<FrameworkMethod> particles = atomicTest.getParticles();
66+
...
67+
}
6268
...
6369
}
6470

@@ -242,11 +248,12 @@ The preceding **ServiceLoader** provider configuration files declare a **JUnit F
242248
**RunnerWatcher** provides callbacks for events in the lifecycle of **`ParentRunner`** objects. It receives the following notifications:
243249
* A **`ParentRunner`** object is about to run.
244250
* A **`ParentRunner`** object has finished running.
245-
* [TestClassWatcher](https://github.com/Nordstrom/JUnit-Foundation/blob/master/src/main/java/com/nordstrom/automation/junit/TestClassWatcher.java)
246-
**TestClassWatcher** provides callbacks for events in the lifecycle of **`TestClass`** objects. It receives the following notifications:
247-
* A **`TestClass`** object has been created to represent a JUnit test class or suite. Each **`TestClass`** has a one-to-one relationship with the JUnit runner that created it.
251+
* [TestClassWatcher2](https://github.com/Nordstrom/JUnit-Foundation/blob/master/src/main/java/com/nordstrom/automation/junit/TestClassWatcher2.java)
252+
**TestClassWatcher2** provides callbacks for events in the lifecycle of **`TestClass`** objects. It receives the following notifications:
253+
* A **`TestClass`** object has been created to represent a JUnit test class or suite. Each **`TestClass`** has a one-to-one relationship with the JUnit runner that created it. (see **NOTE**)
248254
* A **`TestClass`** object has been scheduled to run. This signals that the first child of the JUnit test class or suite is about start.
249255
* A **`TestClass`** object has finished running. This signals that the last child of the JUnit test class or suite is done.
256+
* **NOTE** - This interface supercedes a prior version, adding the runner object to start/finish notifications. Test executers like Maven Surefire create suite runners for their own purposes (e.g. - parallel execution context). This breaks the one-to-one relationship between **`TestClass`** objects and runners. Consequently, the **`TestClass`** object cannot be assumed to represent a unique context.
250257
* [TestObjectWatcher](https://github.com/Nordstrom/JUnit-Foundation/blob/master/src/main/java/com/nordstrom/automation/junit/TestObjectWatcher.java)
251258
**TestObjectWatcher** provides callbacks for events in the lifecycle of Java test class instances. It receives the following notification:
252259
* An instance of a JUnit test class has been created for the execution of a single `atomic test`.

src/main/java/com/nordstrom/automation/junit/CreateTestClass.java

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,12 +24,14 @@
2424
@SuppressWarnings("squid:S1118")
2525
public class CreateTestClass {
2626
private static final ServiceLoader<TestClassWatcher> classWatcherLoader;
27+
private static final ServiceLoader<TestClassWatcher2> classWatcher2Loader;
2728
private static final Logger LOGGER = LoggerFactory.getLogger(CreateTestClass.class);
2829
private static final Map<TestClass, Object> TESTCLASS_TO_RUNNER = new ConcurrentHashMap<>();
2930
private static final Map<Object, TestClass> METHOD_TO_TESTCLASS = new ConcurrentHashMap<>();
3031

3132
static {
3233
classWatcherLoader = ServiceLoader.load(TestClassWatcher.class);
34+
classWatcher2Loader = ServiceLoader.load(TestClassWatcher2.class);
3335
}
3436

3537
/**
@@ -53,6 +55,9 @@ public static TestClass intercept(@This final Object runner, @SuperCall final Ca
5355
for (TestClassWatcher watcher : classWatcherLoader) {
5456
watcher.testClassCreated(testClass, runner);
5557
}
58+
for (TestClassWatcher2 watcher : classWatcher2Loader) {
59+
watcher.testClassCreated(testClass, runner);
60+
}
5661

5762
attachRunnerScheduler(testClass, runner);
5863
return testClass;
@@ -67,7 +72,7 @@ public static TestClass intercept(@This final Object runner, @SuperCall final Ca
6772
private static void attachRunnerScheduler(final TestClass testClass, final Object runner) {
6873
try {
6974
RunnerScheduler scheduler = getFieldValue(runner, "scheduler");
70-
setFieldValue(runner, "scheduler", createRunnerScheduler(testClass, scheduler));
75+
setFieldValue(runner, "scheduler", createRunnerScheduler(testClass, runner, scheduler));
7176
} catch (IllegalAccessException | NoSuchFieldException | SecurityException | IllegalArgumentException e) {
7277
LOGGER.warn("Unable to attach notifying runner scheduler", e);
7378
}
@@ -77,10 +82,12 @@ private static void attachRunnerScheduler(final TestClass testClass, final Objec
7782
* Create notifying runner scheduler, which forwards to the previous scheduler if specified.
7883
*
7984
* @param testClass {@link TestClass} object that was just created
85+
* @param runner {@link ParentRunner} for the specified test class
8086
* @param scheduler runner scheduler that's currently attached to the specified runner (may be {@code null})
8187
* @return new notifying runner scheduler
8288
*/
83-
private static RunnerScheduler createRunnerScheduler(final TestClass testClass, final RunnerScheduler scheduler) {
89+
private static RunnerScheduler createRunnerScheduler(final TestClass testClass,
90+
final Object runner, final RunnerScheduler scheduler) {
8491
return new RunnerScheduler() {
8592
private AtomicBoolean scheduled = new AtomicBoolean(false);
8693

@@ -89,6 +96,9 @@ public void schedule(Runnable childStatement) {
8996
for (TestClassWatcher watcher : classWatcherLoader) {
9097
watcher.testClassStarted(testClass);
9198
}
99+
for (TestClassWatcher2 watcher : classWatcher2Loader) {
100+
watcher.testClassStarted(testClass, runner);
101+
}
92102
}
93103

94104
RunReflectiveCall.fireTestStarted(testClass, childStatement);
@@ -106,6 +116,9 @@ public void finished() {
106116
for (TestClassWatcher watcher : classWatcherLoader) {
107117
watcher.testClassFinished(testClass);
108118
}
119+
for (TestClassWatcher2 watcher : classWatcher2Loader) {
120+
watcher.testClassFinished(testClass, runner);
121+
}
109122
}
110123
};
111124
}

src/main/java/com/nordstrom/automation/junit/TestClassWatcher.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,13 +20,15 @@ public interface TestClassWatcher {
2020
* Called when a runner (test class or suite) is about to be started.
2121
*
2222
* @param testClass {@link TestClass} object for the parent runner
23+
* @deprecated Use {@link TestClassWatcher2#testClassStarted(TestClass, Object)} instead
2324
*/
2425
void testClassStarted(TestClass testClass);
2526

2627
/**
2728
* Called when a runner (test class or suite) has finished.
2829
*
2930
* @param testClass {@link TestClass} object for the parent runner
31+
* @deprecated Use {@link TestClassWatcher2#testClassFinished(TestClass, Object)} instead
3032
*/
3133
void testClassFinished(TestClass testClass);
3234
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
package com.nordstrom.automation.junit;
2+
3+
import org.junit.runners.model.TestClass;
4+
5+
/**
6+
* This interface defines the methods implemented by JUnit TestClass watchers. These watchers are registered via a
7+
* ServiceLoader provider configuration file.
8+
*/
9+
public interface TestClassWatcher2 extends TestClassWatcher {
10+
11+
/**
12+
* Called when a runner (test class or suite) is about to be started.
13+
*
14+
* @param testClass {@link TestClass} object for the parent runner
15+
* @param runner JUnit test runner
16+
*/
17+
void testClassStarted(TestClass testClass, Object runner);
18+
19+
/**
20+
* Called when a runner (test class or suite) has finished.
21+
*
22+
* @param testClass {@link TestClass} object for the parent runner
23+
* @param runner JUnit test runner
24+
*/
25+
void testClassFinished(TestClass testClass, Object runner);
26+
}

0 commit comments

Comments
 (0)