Problem with @RunWith(PowerMockRunner.class)

4,648 views
Skip to first unread message

TomInDenver

unread,
Aug 3, 2009, 7:17:40 PM8/3/09
to PowerMock
Hi,

We are using the PowerMock 1.2.5 jars, JUNIT 4.6, and JRE 1.6.0.12. I
am running on Windows XP, SP3.

We use JAXB and I am having a problem trying to create one of the JAXB
related classes (SchemaFactory) in my unit test class when using
@RunWith(PowerMockRunner.class). It gets an exception with the
following message:

java.lang.IllegalArgumentException: No SchemaFactory that implements
the schema language specified by: http://www.w3.org/2001/XMLSchema
could be loaded

If I take the @RunWith(PowerMockRunner.class) line away, I do not get
the exception.

To troubleshoot, I thought I’d print my environment out in both
scenarios and compare. What I found was that when runing with
PowerMock, my PATH environment variable contains JRE 1.6.0 instead of
JRE 1.6.0.12 (hmmmm). I had the earlier version still installed on my
system, so I renamed the JRE directory of the earlier version. When I
ran again, I saw JRE 1.6.0.12 in my PATH which is correct. But I still
got the exception. Bummer.

Do you know what could be happening or how to resolve ? The unit test
code (thru the part that fails) is below. Any help would be greatly
appreciated. Thanks.
Tom Vicker
(303) 721-4655

package com.snp.ciq.test;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail;
import java.util.Map;
import java.util.Properties;
import javax.xml.XMLConstants;
import javax.xml.validation.SchemaFactory;
import org.junit.After;import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import com.snp.ciq.CiqHelper;
import com.snp.unildr.XFLApplication;

@RunWith(PowerMockRunner.class)
@PrepareForTest( { XFLApplication.class })
public class CiqHelperTest {

CiqHelper ciqHelper;

@Before
public void setUp() throws Exception {
try {
Map<String, String> env = System.getenv();
for (Map.Entry<String,String> entry : env.entrySet()) {
System.out.println(entry.getKey() + ", " +
entry.getValue());
}

SchemaFactory sf = SchemaFactory.newInstance
(XMLConstants.W3C_XML_SCHEMA_NS_URI);
ciqHelper = new CiqHelper();
}
catch (Exception e) {
String msg = e.getMessage();
}
}
. . .

Johan Haleby

unread,
Aug 4, 2009, 3:00:17 AM8/4/09
to powe...@googlegroups.com

Hi,

I think I may have a clue about what's going on but it's not easy to tell exactly how to fix it. If possible could you try to add this to the beginning of your setup or test method:

Thread.currentThread().setContextClassLoader(this.getClass().getClassLoader());

and see if you notice any difference?

/Johan

TomInDenver

unread,
Aug 4, 2009, 10:07:14 AM8/4/09
to PowerMock
Hi Johan,

Your suggestion worked! The exception no longer occurs. Now I need to
finish writing the rest of the test and hopefully there won't be any
other issues.

Now I am curious as to why it worked. If its not too much trouble,
could you provide an explanation ? I can deduce that it has something
to do with using the correct ClassLoader in the thread that is being
invoked, but I do not understand it fully. I certainly would have
never thought of including such a statement in my test.

Thanks very much!

Tom Vicker

On Aug 4, 1:00 am, Johan Haleby <johan.hal...@gmail.com> wrote:
> Hi,
>
> I think I may have a clue about what's going on but it's not easy to tell
> exactly how to fix it. If possible could you try to add this to the
> beginning of your setup or test method:
>
> Thread.currentThread().setContextClassLoader(this.getClass().getClassLoader());
>
> and see if you notice any difference?
>
> /Johan
>

Johan Haleby

unread,
Aug 4, 2009, 11:41:55 AM8/4/09
to powe...@googlegroups.com
Hi,

I'm very glad to hear that it solved your problem because in PowerMock 1.3 changing the context classloader (CL) will be done automatically for you. The reason why you get the error is most likely because you load a particular class by PowerMock's classloader (XFLApplication.class) and then you integrate with a framework that does "something" (such as initializing a class) using reflection and using the thread context classloader. This means that some logic in that framework fails because some classes are loaded by PowerMock CL and others are loaded by the System/Bootstrap CL which will lead to that the framework tries to load a (in your case) XMLSchemaFactory which it cannot find. You can solve this by using @PowerMockIgnore as well but since we're changing the thread context CL for you in 1.3 it's probably better to set the thread context CL manually for now. Test that uses @PowerMockIgnore may not be backward compatible in version 1.3! The solution would then be either to remove @PowerMockIgnore completely or update the ignore-string passed to @PowerMockIgnore.

/Johan

On Tue, Aug 4, 2009 at 4:07 PM, TomInDenver <tomv...@gmail.com> wrote

TomInDenver

unread,
Aug 4, 2009, 12:41:50 PM8/4/09
to PowerMock
Johan,

Thanks for the explanation! I am sure this will help others as well
until they get 1.3. I am not knowledgeable on ClassLoaders so this was
educational. I guess I thought all ClassLoaders would just use the
same classpath, but it sounds like there is a lot more to it in the
class lookup logic.

Tom

On Aug 4, 9:41 am, Johan Haleby <johan.hal...@gmail.com> wrote:
> Hi,
>
> I'm very glad to hear that it solved your problem because in PowerMock 1.3
> changing the context classloader (CL) will be done automatically for you.
> The reason why you get the error is most likely because you load a
> particular class by PowerMock's classloader (XFLApplication.class) and then
> you integrate with a framework that does "something" (such as initializing a
> class) using reflection and using the thread context classloader. This means
> that some logic in that framework fails because some classes are loaded by
> PowerMock CL and others are loaded by the System/Bootstrap CL which will
> lead to that the framework tries to load a (in your case) XMLSchemaFactory
> which it cannot find. You can solve this by using @PowerMockIgnore as well
> but since we're changing the thread context CL for you in 1.3 it's probably
> better to set the thread context CL manually for now. Test that uses
> @PowerMockIgnore may *not* be backward compatible in version 1.3! The
> solution would then be either to remove @PowerMockIgnore completely or
> update the ignore-string passed to @PowerMockIgnore.
>
> /Johan
>
> On Tue, Aug 4, 2009 at 4:07 PM, TomInDenver <tomvic...@gmail.com> wrote

Johan Haleby

unread,
Aug 5, 2009, 2:47:32 AM8/5/09
to powe...@googlegroups.com
Well I guess you can say (in the general sense at least) that all classloaders share the same classpath but it's not necessary. But I think the thing here is not that the context CL and PowerMock CL doesn't share the same classpath. Rather I believe that your framework loads a class (X) using reflection using the context CL and then has some logic that checks something like if X is instanceOf Y (which it usually is) but Y has now been loaded by PowerMock CL during the test so the if-statement now return false (because X & Y are loaded by different CL's). Since that if-statement failed it then tries to load a SchemaFactory instead which is not present on the classpath at all.

Of course I'm not 100% sure if this is true for your framework but I've seen this for other frameworks such as JDom.

/Johan
Reply all
Reply to author
Forward
0 new messages