Skip to content

Commit 769895b

Browse files
authored
Work around an execution issue that prevented use of the PowerMock runner (#81)
Once activated, PowerMock apparently wants to proxy everything. One side effect of this proclivity is that it can subtly alter objects in obscure parts of the implementation, far removed from any intended code. This can cause anomalous behavior, like the object-type mismatch that occurred deep in the bowels of Apache Commons Configuration. To avoid the object-type mismatch, I now instantiate the configuration object in the interceptor for the run method, prior to the execution of PowerMockRunner. These revisions include PowerMock unit tests. The JUnit Foundation library is targeted at Java 7, but Mockito requires Java 8, so I updated the project to compile for Java 7 and execute tests in Java 8. This effort was very useful, because figuring out how to get this to work revealed that I didn't need the maven-toolchain-plugin, the removal of which allowed me to eliminate the Eclipse lifecycle-mapping plugin.
1 parent 3b89ba2 commit 769895b

File tree

7 files changed

+113
-45
lines changed

7 files changed

+113
-45
lines changed

pom.xml

Lines changed: 37 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,8 @@
2727

2828
<properties>
2929
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
30-
<maven.compiler.source>1.7</maven.compiler.source>
31-
<maven.compiler.target>1.7</maven.compiler.target>
30+
<compile-jdk.version>1.7</compile-jdk.version>
31+
<test-jdk.version>1.8</test-jdk.version>
3232
<java-utils.version>1.9.3</java-utils.version>
3333
<settings.version>2.3.3</settings.version>
3434
<junit.version>4.13.1</junit.version>
@@ -37,7 +37,9 @@
3737
<logback.version>1.2.3</logback.version>
3838
<guava.version>28.1-android</guava.version>
3939
<junitparams.version>1.1.1</junitparams.version>
40+
<powermock.version>2.0.9</powermock.version>
4041
<toolchains-plugin.version>1.1</toolchains-plugin.version>
42+
<compiler-plugin.version>3.8.1</compiler-plugin.version>
4143
<surefire-plugin.version>2.22.0</surefire-plugin.version>
4244
<source-plugin.version>3.2.0</source-plugin.version>
4345
<javadoc-plugin.version>3.1.1</javadoc-plugin.version>
@@ -113,6 +115,16 @@
113115
<artifactId>JUnitParams</artifactId>
114116
<version>${junitparams.version}</version>
115117
</dependency>
118+
<dependency>
119+
<groupId>org.powermock</groupId>
120+
<artifactId>powermock-module-junit4</artifactId>
121+
<version>${powermock.version}</version>
122+
</dependency>
123+
<dependency>
124+
<groupId>org.powermock</groupId>
125+
<artifactId>powermock-api-mockito2</artifactId>
126+
<version>${powermock.version}</version>
127+
</dependency>
116128
</dependencies>
117129
</dependencyManagement>
118130

@@ -156,15 +168,25 @@
156168
<artifactId>JUnitParams</artifactId>
157169
<scope>test</scope>
158170
</dependency>
171+
<dependency>
172+
<groupId>org.powermock</groupId>
173+
<artifactId>powermock-module-junit4</artifactId>
174+
<scope>test</scope>
175+
</dependency>
176+
<dependency>
177+
<groupId>org.powermock</groupId>
178+
<artifactId>powermock-api-mockito2</artifactId>
179+
<scope>test</scope>
180+
</dependency>
159181
</dependencies>
160182

161183
<build>
162184
<pluginManagement>
163185
<plugins>
164186
<plugin>
165187
<groupId>org.apache.maven.plugins</groupId>
166-
<artifactId>maven-toolchains-plugin</artifactId>
167-
<version>${toolchains-plugin.version}</version>
188+
<artifactId>maven-compiler-plugin</artifactId>
189+
<version>${compiler-plugin.version}</version>
168190
</plugin>
169191
<plugin>
170192
<groupId>org.apache.maven.plugins</groupId>
@@ -201,57 +223,30 @@
201223
<artifactId>maven-jar-plugin</artifactId>
202224
<version>${jar-plugin.version}</version>
203225
</plugin>
204-
<plugin>
205-
<groupId>org.eclipse.m2e</groupId>
206-
<artifactId>lifecycle-mapping</artifactId>
207-
<version>1.0.0</version>
208-
<configuration>
209-
<lifecycleMappingMetadata>
210-
<pluginExecutions>
211-
<pluginExecution>
212-
<pluginExecutionFilter>
213-
<groupId>org.apache.maven.plugins</groupId>
214-
<artifactId>maven-toolchains-plugin</artifactId>
215-
<versionRange>[1.0.0,)</versionRange>
216-
<goals>
217-
<goal>toolchain</goal>
218-
</goals>
219-
</pluginExecutionFilter>
220-
<action>
221-
<execute />
222-
</action>
223-
</pluginExecution>
224-
</pluginExecutions>
225-
</lifecycleMappingMetadata>
226-
</configuration>
227-
</plugin>
228226
</plugins>
229227
</pluginManagement>
230228

231229
<plugins>
232230
<plugin>
233231
<groupId>org.apache.maven.plugins</groupId>
234-
<artifactId>maven-toolchains-plugin</artifactId>
235-
<executions>
236-
<execution>
237-
<goals>
238-
<goal>toolchain</goal>
239-
</goals>
240-
</execution>
241-
</executions>
232+
<artifactId>maven-compiler-plugin</artifactId>
242233
<configuration>
243-
<toolchains>
244-
<jdk>
245-
<version>1.7</version>
246-
<vendor>oracle</vendor>
247-
</jdk>
248-
</toolchains>
234+
<source>${compile-jdk.version}</source>
235+
<target>${compile-jdk.version}</target>
236+
<jdkToolchain>
237+
<version>${compile-jdk.version}</version>
238+
<vendor>oracle</vendor>
239+
</jdkToolchain>
249240
</configuration>
250241
</plugin>
251242
<plugin>
252243
<groupId>org.apache.maven.plugins</groupId>
253244
<artifactId>maven-surefire-plugin</artifactId>
254245
<configuration>
246+
<jdkToolchain>
247+
<version>${test-jdk.version}</version>
248+
<vendor>oracle</vendor>
249+
</jdkToolchain>
255250
<argLine>-javaagent:src/test/resources/test-agent.jar</argLine>
256251
</configuration>
257252
</plugin>

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -312,6 +312,7 @@ public static TestClass getTestClassOf(Object runner) {
312312
/**
313313
* Get the atomic test object for the specified class runner.
314314
*
315+
* @param <T> data type of runner's children
315316
* @param runner JUnit class runner
316317
* @return {@link AtomicTest} object (may be {@code null})
317318
*/

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,7 @@ static Object getThreadRunner() {
138138
*/
139139
static boolean fireRunStarted(Object runner) {
140140
if (startNotified.add(runner.toString())) {
141+
JUnitConfig.getConfig();
141142
List<?> grandchildren = LifecycleHooks.invoke(runner, "getChildren");
142143
for (Object grandchild : grandchildren) {
143144
CHILD_TO_PARENT.put(grandchild, runner);

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

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
import java.lang.IllegalAccessException;
1111

1212
import org.junit.internal.runners.model.ReflectiveCallable;
13+
import org.junit.runner.Description;
1314
import org.slf4j.Logger;
1415
import org.slf4j.LoggerFactory;
1516

@@ -123,7 +124,8 @@ private static boolean fireBeforeInvocation(Object runner, Object child, Reflect
123124
if (0 == depthGauge.increaseDepth()) {
124125
if (LOGGER.isDebugEnabled()) {
125126
try {
126-
LOGGER.debug("beforeInvocation: {}", LifecycleHooks.invoke(runner, "describeChild", child));
127+
LOGGER.debug("beforeInvocation: {}",
128+
(Description) LifecycleHooks.invoke(runner, "describeChild", child));
127129
} catch (Throwable t) {
128130
// nothing to do here
129131
}
@@ -157,7 +159,8 @@ private static boolean fireAfterInvocation(Object runner, Object child, Reflecti
157159
if (0 == depthGauge.decreaseDepth()) {
158160
if (LOGGER.isDebugEnabled()) {
159161
try {
160-
LOGGER.debug("afterInvocation: {}", LifecycleHooks.invoke(runner, "describeChild", child));
162+
LOGGER.debug("afterInvocation: {}",
163+
(Description) LifecycleHooks.invoke(runner, "describeChild", child));
161164
} catch (Throwable t) {
162165
// nothing to do here
163166
}

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ public class RunWithCompleteAssignment {
2828
* <p>
2929
* <b>NOTE</b>: This method relies on the "theory catalyst" created by the {@link MethodBlock}
3030
* class to attach the class runner to the thread and create a new atomic test for the target
31-
* method. The actual method block statement is retrieved from <b>MethodBlock<b> and executed,
31+
* method. The actual method block statement is retrieved from <b>MethodBlock</b> and executed,
3232
* publishing a complete set of test lifecycle events.
3333
*
3434
* @param anchor current {@code TheoryAnchor} statement
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
package com.nordstrom.automation.junit;
2+
3+
import static org.hamcrest.CoreMatchers.equalTo;
4+
import static org.hamcrest.CoreMatchers.nullValue;
5+
import static org.hamcrest.MatcherAssert.assertThat;
6+
import static org.mockito.Mockito.when;
7+
import static org.powermock.api.mockito.PowerMockito.mockStatic;
8+
9+
import org.junit.Test;
10+
import org.junit.runner.RunWith;
11+
import org.junit.runners.BlockJUnit4ClassRunner;
12+
import org.powermock.core.classloader.annotations.PrepareForTest;
13+
import org.powermock.modules.junit4.PowerMockRunner;
14+
import org.powermock.modules.junit4.PowerMockRunnerDelegate;
15+
16+
@RunWith(PowerMockRunner.class)
17+
@PowerMockRunnerDelegate(BlockJUnit4ClassRunner.class)
18+
@PrepareForTest(PowerMockCases.StaticClass.class)
19+
public class PowerMockCases {
20+
21+
@Test
22+
public void testHappyPath() {
23+
mockStatic(StaticClass.class);
24+
when(StaticClass.staticMethod()).thenReturn("mocked");
25+
assertThat(StaticClass.staticMethod(), equalTo("mocked"));
26+
}
27+
28+
@Test
29+
public void testFailure() {
30+
mockStatic(StaticClass.class);
31+
when(StaticClass.staticMethod()).thenReturn("mocked");
32+
assertThat(StaticClass.staticMethod(), nullValue());
33+
}
34+
35+
static class StaticClass {
36+
public static String staticMethod() {
37+
return null;
38+
}
39+
}
40+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
package com.nordstrom.automation.junit;
2+
3+
import static org.junit.Assert.assertFalse;
4+
import static org.testng.Assert.assertEquals;
5+
6+
import org.junit.runner.JUnitCore;
7+
import org.junit.runner.Result;
8+
import org.testng.annotations.Test;
9+
10+
public class PowerMockTest {
11+
12+
@Test
13+
public void verifyMethodInterception() {
14+
RunListenerAdapter rla = new RunListenerAdapter();
15+
16+
JUnitCore runner = new JUnitCore();
17+
runner.addListener(rla);
18+
Result result = runner.run(PowerMockCases.class);
19+
assertFalse(result.wasSuccessful());
20+
21+
assertEquals(rla.getPassedTests().size(), 1, "Incorrect passed test count");
22+
assertEquals(rla.getPassedTests().get(0).getDisplayName(),
23+
"testHappyPath(com.nordstrom.automation.junit.PowerMockCases)", "Incorrect passed test name");
24+
assertEquals(rla.getFailedTests().size(), 1, "Incorrect failed test count");
25+
assertEquals(rla.getIgnoredTests().size(), 0, "Incorrect ignored test count");
26+
}
27+
28+
}

0 commit comments

Comments
 (0)