Skip to content

Commit 1ffc868

Browse files
authored
Merge pull request #11 from Nordstrom/pr/use-more-junit
Pr/use more junit
2 parents 72e1e39 + c03e70b commit 1ffc868

19 files changed

+743
-459
lines changed

pom.xml

Lines changed: 1 addition & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
<modelVersion>4.0.0</modelVersion>
33
<groupId>com.nordstrom.tools</groupId>
44
<artifactId>junit-foundation</artifactId>
5-
<version>5.0.1-SNAPSHOT</version>
5+
<version>6.0.0-SNAPSHOT</version>
66
<packaging>jar</packaging>
77

88
<name>JUnit Foundation</name>
@@ -147,11 +147,6 @@
147147
<target>1.8</target>
148148
</configuration>
149149
</plugin>
150-
<plugin>
151-
<groupId>net.bytebuddy</groupId>
152-
<artifactId>byte-buddy-maven-plugin</artifactId>
153-
<version>${bytebuddy.version}</version>
154-
</plugin>
155150
<plugin>
156151
<groupId>org.apache.maven.plugins</groupId>
157152
<artifactId>maven-surefire-plugin</artifactId>
@@ -191,24 +186,6 @@
191186
</pluginManagement>
192187

193188
<plugins>
194-
<plugin>
195-
<groupId>net.bytebuddy</groupId>
196-
<artifactId>byte-buddy-maven-plugin</artifactId>
197-
<executions>
198-
<execution>
199-
<goals>
200-
<goal>transform-test</goal>
201-
</goals>
202-
</execution>
203-
</executions>
204-
<configuration>
205-
<transformations>
206-
<transformation>
207-
<plugin>com.nordstrom.automation.junit.HookInstallingPlugin</plugin>
208-
</transformation>
209-
</transformations>
210-
</configuration>
211-
</plugin>
212189
<plugin>
213190
<groupId>org.apache.maven.plugins</groupId>
214191
<artifactId>maven-surefire-plugin</artifactId>
Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
package com.nordstrom.automation.junit;
2+
3+
import static com.nordstrom.automation.junit.LifecycleHooks.invoke;
4+
5+
import java.util.List;
6+
7+
import org.junit.After;
8+
import org.junit.AfterClass;
9+
import org.junit.Before;
10+
import org.junit.BeforeClass;
11+
import org.junit.Ignore;
12+
import org.junit.Test;
13+
import org.junit.runners.model.FrameworkMethod;
14+
import org.junit.runners.model.TestClass;
15+
16+
/**
17+
* This class represents an atomic JUnit test, which is composed of a core {@link Test &#64;Test} method and
18+
* the configuration methods that run with it ({@link Before &#64;Before}, {@link org.junit.After &#64;After},
19+
* {@link org.junit.BeforeClass &#64;BeforeClass}, and {@link AfterClass &#64;AfterClass}).
20+
*/
21+
@Ignore
22+
@SuppressWarnings("all")
23+
public class AtomicTest {
24+
private final Object runner;
25+
private final TestClass testClass;
26+
private final FrameworkMethod identity;
27+
private final List<FrameworkMethod> particles;
28+
private Throwable thrown;
29+
30+
public AtomicTest(Object runner, TestClass testClass, FrameworkMethod testMethod) {
31+
this.runner = runner;
32+
this.testClass = testClass;
33+
this.identity = testMethod;
34+
this.particles = invoke(runner, "getChildren");
35+
}
36+
37+
/**
38+
* Get the runner for this atomic test.
39+
*
40+
* @return {@code BlockJUnit4ClassRunner} object
41+
*/
42+
public Object getRunner() {
43+
return runner;
44+
}
45+
46+
/**
47+
* Get the test class associated with this atomic test.
48+
*
49+
* @return {@link TestClass} object associated with this atomic test
50+
*/
51+
public TestClass getTestClass() {
52+
return testClass;
53+
}
54+
55+
/**
56+
* Get the "identity" method for this atomic test - the core {@link Test &#64;Test} method.
57+
*
58+
* @return core method associated with this atomic test
59+
*/
60+
public FrameworkMethod getIdentity() {
61+
return identity;
62+
}
63+
64+
/**
65+
* Get the "particle" methods of which this atomic test is composed.
66+
*
67+
* @return list of methods that compose this atomic test
68+
*/
69+
public List<FrameworkMethod> getParticles() {
70+
return particles;
71+
}
72+
73+
/**
74+
* Determine if this atomic test includes configuration methods.
75+
*
76+
* @return {@code true} if this atomic test includes configuration; otherwise {@code false}
77+
*/
78+
public boolean hasConfiguration() {
79+
return (particles.size() > 1);
80+
}
81+
82+
/**
83+
* Set the exception for this atomic test.
84+
*
85+
* @param thrown exception for this atomic test
86+
*/
87+
void setThrowable(Throwable thrown) {
88+
this.thrown = thrown;
89+
}
90+
91+
/**
92+
* Get the exception for this atomic test.
93+
*
94+
* @return exception for this atomic test; {@code null} if test finished normally
95+
*/
96+
public Throwable getThrowable() {
97+
return thrown;
98+
}
99+
100+
/**
101+
* Determine if this atomic test includes the specified method.
102+
*
103+
* @param method {@link FrameworkMethod} object
104+
* @return {@code true} if this atomic test includes the specified method; otherwise {@code false}
105+
*/
106+
public boolean includes(FrameworkMethod method) {
107+
return particles.contains(method);
108+
}
109+
}
Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
package com.nordstrom.automation.junit;
2+
3+
import static com.nordstrom.automation.junit.LifecycleHooks.getFieldValue;
4+
import static com.nordstrom.automation.junit.LifecycleHooks.setFieldValue;
5+
6+
import java.util.Map;
7+
import java.util.ServiceLoader;
8+
import java.util.concurrent.Callable;
9+
import java.util.concurrent.ConcurrentHashMap;
10+
import java.util.concurrent.atomic.AtomicBoolean;
11+
12+
import org.junit.runners.model.RunnerScheduler;
13+
import org.junit.runners.model.TestClass;
14+
import org.slf4j.Logger;
15+
import org.slf4j.LoggerFactory;
16+
17+
import net.bytebuddy.implementation.bind.annotation.SuperCall;
18+
import net.bytebuddy.implementation.bind.annotation.This;
19+
20+
/**
21+
* This class declares the interceptor for the {@link org.junit.runners.ParentRunner#createTestClass
22+
* createTestClass} method.
23+
*/
24+
@SuppressWarnings("squid:S1118")
25+
public class CreateTestClass {
26+
private static final ServiceLoader<TestClassWatcher> classWatcherLoader;
27+
private static final Logger LOGGER = LoggerFactory.getLogger(CreateTestClass.class);
28+
private static final Map<TestClass, Object> TESTCLASS_TO_RUNNER = new ConcurrentHashMap<>();
29+
30+
static {
31+
classWatcherLoader = ServiceLoader.load(TestClassWatcher.class);
32+
}
33+
34+
/**
35+
* Interceptor for the {@link org.junit.runners.ParentRunner#createTestClass createTestClass} method.
36+
*
37+
* @param runner underlying test runner
38+
* @param proxy callable proxy for the intercepted method
39+
* @return new {@link TestClass} object
40+
* @throws Exception {@code anything} (exception thrown by the intercepted method)
41+
*/
42+
public static TestClass intercept(@This final Object runner, @SuperCall final Callable<?> proxy)
43+
throws Exception {
44+
45+
TestClass testClass = (TestClass) proxy.call();
46+
TESTCLASS_TO_RUNNER.put(testClass, runner);
47+
48+
for (TestClassWatcher watcher : classWatcherLoader) {
49+
watcher.testClassCreated(testClass, runner);
50+
}
51+
52+
attachRunnerScheduler(testClass, runner);
53+
return testClass;
54+
}
55+
56+
/**
57+
* Attach lifecycle-reporting runner scheduler to the specified parent runner.
58+
*
59+
* @param testClass {@link TestClass} object that was just created
60+
* @param runner {@link ParentRunner} for the specified test class
61+
*/
62+
private static void attachRunnerScheduler(final TestClass testClass, final Object runner) {
63+
try {
64+
RunnerScheduler scheduler = getFieldValue(runner, "scheduler");
65+
setFieldValue(runner, "scheduler", createRunnerScheduler(testClass, scheduler));
66+
} catch (IllegalAccessException | NoSuchFieldException | SecurityException | IllegalArgumentException e) {
67+
LOGGER.warn("Unable to attach notifying runner scheduler", e);
68+
}
69+
}
70+
71+
/**
72+
* Create notifying runner scheduler, which forwards to the previous scheduler if specified.
73+
*
74+
* @param testClass {@link TestClass} object that was just created
75+
* @param scheduler runner scheduler that's currently attached to the specified runner (may be {@code null})
76+
* @return new notifying runner scheduler
77+
*/
78+
private static RunnerScheduler createRunnerScheduler(final TestClass testClass, final RunnerScheduler scheduler) {
79+
return new RunnerScheduler() {
80+
private AtomicBoolean scheduled = new AtomicBoolean(false);
81+
82+
public void schedule(Runnable childStatement) {
83+
if (scheduled.compareAndSet(false, true)) {
84+
for (TestClassWatcher watcher : classWatcherLoader) {
85+
watcher.testClassStarted(testClass);
86+
}
87+
}
88+
89+
RunReflectiveCall.fireTestStarted(testClass, childStatement);
90+
91+
if (scheduler != null) {
92+
scheduler.schedule(childStatement);
93+
} else {
94+
childStatement.run();
95+
}
96+
97+
RunReflectiveCall.fireTestFinished(testClass);
98+
}
99+
100+
public void finished() {
101+
for (TestClassWatcher watcher : classWatcherLoader) {
102+
watcher.testClassFinished(testClass);
103+
}
104+
}
105+
};
106+
}
107+
108+
/**
109+
* Get the parent runner associate with the specified test class.
110+
*
111+
* @param testClass {@link TestClass} object
112+
* @return {@code ParentRunner} object associated with the specified test class
113+
*/
114+
static Object getRunnerFor(TestClass testClass) {
115+
Object runner = TESTCLASS_TO_RUNNER.get(testClass);
116+
if (runner != null) {
117+
return runner;
118+
}
119+
throw new IllegalArgumentException("No associated runner was found for specified test class");
120+
}
121+
}

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

Lines changed: 0 additions & 31 deletions
This file was deleted.

0 commit comments

Comments
 (0)