Q&A

1: PowerMockRunner threw

java.lang.NoClassDefFoundError: org/junit/internal/runners/BeforeAndAfterRunner

or

java.lang.SecurityException: class "org.junit.internal.runners.TestClass"'s signer information does not match signer information of other classes in the same package

The exception. What’s wrong?

You may have used an incorrect PowerMockRunner. There is a Runner program for JUnit 4.4 and later, and another Runner program for JUnit 4.0-4.3 (although the latter also works with some older minor versions of JUnit 4.4). Try from the org. Powermock. Modules. The takeup. PowerMockRunner switch to org. Powermock. Modules. Takeup. Legacy. PowerMockRunner, and vice versa. Check out Getting Started to learn how to configure in Maven.

2: How can I fix Cobertura giving me errors or producing strange results when RUNNING PowerMock tests in Maven?

Use either of the following to solve the problem: a: Upgrade to Cobertura 2.4+ or b: follow the instructions on this blog, or c: add the following to your POM.xml file:

   <build>
       <plugins>
           <plugin>
               <artifactId>maven-surefire-plugin</artifactId>
               <configuration>
                   <forkMode>pertest</forkMode>
               </configuration>
           </plugin>
       </plugins>
   </build>
Copy the code

3: I get a ClassCastException error from DocumentBuilderFactory, SaxParserFactory, or another XML-related class. What should I do?

The reason is that the XML framework tries to instantiate classes using reflection, performs this operation from the thread-context classloader (PowerMock’s classloader), and then tries to assign the created object to fields that are not loaded by the same classloader. When this happens, you need to use the @PowerMockIgnore annotation to tell PowerMock to defer the loading of a package to the system classloader. What you need to ignore are case-specific, but often XML frameworks or packages that interact with them. Such as @ PowerMockIgnore ({” org. XML. \ * “, “javax.mail. XML. \ *”}). Another option is to try booting with our Java Agent.

4: I can’t mock java.lang, java.net, java.io, or any other system class. Why?

This is because they are loaded by Java’s boot classloader and cannot be manipulated by PowerMock’s classloader with bytecode. Starting with PowerMock 1.2.5, there is a workaround, so take a look at this simple example to see how it works.

5: When emulating Hibernate, I get an error like the following:

java.lang.ClassCastException: org.hibernate.ejb.HibernatePersistence cannot be cast to javax.persistence.spi.PersistenceProvider
    at javax.persistence.Persistence.findAllProviders(Persistence.java:80)
    at javax.persistence.Persistence.createEntityManagerFactory(Persistence.java:49)
    at javax.persistence.Persistence.createEntityManagerFactory(Persistence.java:34)...Copy the code

Solution: Upgrade to PowerMock 1.3+ or use @PowerMockIgnore(” Javax.persistence.*”) at the class level of the test.

6: Log4j gives me the following (or similar) error when running PowerMock tests,

log4j:ERROR A "org.apache.log4j.xml.DOMConfigurator" object is not assignable to a "org.apache.log4j.spi.Configurator" variable.
log4j:ERROR The class "org.apache.log4j.spi.Configurator" was loaded by
log4j:ERROR [org.powermock.core.classloader.MockClassLoader@ 14a55f2] whereas object of type
log4j:ERROR "org.apache.log4j.xml.DOMConfigurator" was loaded by [sun.misc.Launcher$AppClassLoader@ 92e78c].
log4j:ERROR Could not instantiate configurator [org.apache.log4j.xml.DOMConfigurator].
Copy the code

or

Caused by: org.apache.commons.logging.LogConfigurationException:
Invalid class loader hierarchy.  You have more than one version of
'org.apache.commons.logging.Log' visible.which is not allowed.
Copy the code

What should I do now?

There are several different solutions to this:

1: Upgrade to PowerMock 1.3+.

2: Use the @PowerMockIgnore annotation at the class level of the test. For example, if log4j is used, use an annotation: @PowerMockIgnore(“org.apache.log4j.*”); If you use the Commons logging, using annotations @ PowerMockIgnore (” org.apache.com mons. Logging. * “).

3: Add -dlog4j.ignoretcl =true as the virtual machine parameter to your test run configuration.

4: If you are using PowerMock 1.1 or later, use the @MockPolicy annotation and specify the mock policy. For example, if you use SLf4J with log4j, you should also use the @mockPolicy (slf4jmockPolicy.class) annotation, Or if you are using Log4j independently, you should use the @mockPolicy (log4jmockPolicy.class) annotation again. This is the recommended way. Such as:

@RunWith(PowerMockRunner.class)
@MockPolicy(Log4jMockPolicy.class)
public class MyTest {... }Copy the code

5: Create a nice Logger mock class and set the Logger field to this instance. If this field is static, inhibit the static initialization program (using the @ SuppressStaticInitializerFor annotations), and then sets the logger field to mock classes you just created. For testing next org. Apache. Log4j. Appenders and use @ PrepareForTest annotations for testing. Such as:

@RunWith(PowerMockRunner.class)
@SuppressStaticInitializationFor("org.myapp.MyClassUsingLog4J")
@PrepareForTest({Appender.class})
public class MyTest {

	@Before
	public void setUp(a) { Logger loggerMock = createNiceMock(Logger.class); Whitebox.setInternalState(MyClassUsingLog4J.class, loggerMock); . }... }Copy the code

6: Follow the same as the previous step of the process, but not the org.. Apache log4j. Appender class added to the @ PrepareForTest annotations, But the org. Apache. Log4j. That the LogManager class added to @ SuppressStaticInitializerFor annotations. Such as:

@RunWith(PowerMockRunner.class)
@SuppressStaticInitializationFor({ "org.myapp.MyClassUsingLog4J", "org.apache.log4j.LogManager"})
public class MyTest {

	@Before
	public void setUp(a) { Logger loggerMock = createNiceMock(Logger.class); Whitebox.setInternalState(MyClassUsingLog4J.class, loggerMock); . }... }Copy the code

7: You can try using @prepareEverythingFortest annotations (not recommended).

Does PowerMock work with TestNG?

Yes, because PowerMock version 1.3.5 does have basic TestNG support.

8: Is PowerMock an offshoot of EasyMock?

It isn’t. PowerMock extends other mock frameworks, such as EasyMock, with powerful features such as static emulation.

9: Can you use PowerMock with other frameworks that use JUnit Runner?

Yes, you can use PowerMockRule.

10: I am using Java Agent, and Java 7 encounters an error such as “Unable to load Java Agent”, what should I do?

You can try the following solutions:

   <plugin>
       <groupId>org.apache.maven.plugins</groupId>
       <artifactId>maven-surefire-plugin</artifactId>
       <version>2.14</version>
       <configuration>
           <argLine>-javaagent:${settings.localRepository}/org/powermock/powermock-module-javaagent/${powermock.version}/powermock-module-ja vaagent-${powermock.version}.jar -XX:-UseSplitVerifier</argLine>
       </configuration>
   </plugin>
Copy the code

11: I upgraded to version 1.6.5 but PowerMock started throwing exceptions: Org. Powermock. API. The extension. Reporter. MockingFrameworkReporterFactoryImpl could not be located in the classpath..

If you use Maven, add the following to your POM.xml

   <dependency>
       <groupId>org.powermock</groupId>
       <artifactId>powermock-api-mockito-common</artifactId>
       <version>1.6.5</version>
   </dependency>
Copy the code

If you download the complete JAR, download another JAR from Maven Central Repository and add it to your classpath.