Search code examples
javaunit-testingjunitjmockit

ClassLoader throws NullPointerException when trying to partial mock a class with JMockit


Using Eclipse 3.6.1
Java 1.6.0_26
JMockit 0.999.10

UPDATE: I was able to create a SSCCE, which I am posting below:

UPDATE2: Added DaemonHelper. Additionally, if I remove DaemonHelper from the constructor, I get a ClassCircularityError instead. Related?

I'm trying to do a partial mock of a class, while mocking several dependencies of the class, when I get an NPE from the Class loader. The NPE call stack is show below

I have a Daemon Class like so:

public class Daemon extends DaemonParent {

public Daemon(ConfigParent config, DaemonHelper helper) {
    super(config, helper);
}

@Override
public void execute() {
    log("Starting");
    if (config.test()) {
        log("Testing");
    }

    log("Ending");  
}
}

The Daemon has a Parent like so:

public abstract class DaemonParent extends Thread {

protected ConfigParent config;
protected DaemonHelper helper;

public DaemonParent(ConfigParent config, DaemonHelper helper) {
    this.config = config;
    this.helper = helper;
}


public abstract void execute();

public void log(String s) {
    System.out.println(s);
}
}

There is a helper class like :

public class DaemonHelper extends Thread {

}

The Config looks like :

public class ConfigParent {

protected ConfigHelper helper;

public ConfigParent(ConfigHelper helper) {
    this.helper = helper;
}

public boolean test() {
    return false;
}
}

The Config Parent looks like :

public class ConfigParent implements Serializable {

protected ConfigHelper helper;

public ConfigParent(ConfigHelper helper) {
    this.helper = helper;
}

public boolean test() {
    return false;
}
}

And the Test looks like :

public class DaemonTest {

@Test
public void testExecute(final ConfigHelper ch, final DaemonHelper dh) {
    final Config c = new Config(ch);
    final Daemon d = new Daemon(c, dh);

    new NonStrictExpectations(d) {
        {

        }
    };

    d.execute();

    new Verifications() {{
        d.log("Starting");
        d.log("Ending");
    }};
}
}

When I try to run this test, I get the following error. Note this error only pops up when the DaemonParent and Daemon Helper have java.lang.Thread as a superclass:

java.lang.NullPointerException
at java.lang.Thread.interrupted(Unknown Source)
at sun.misc.Resource.getBytes(Unknown Source)
at java.net.URLClassLoader.defineClass(Unknown Source)
at java.net.URLClassLoader.access$000(Unknown Source)
at java.net.URLClassLoader$1.run(Unknown Source)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(Unknown Source)
at java.lang.ClassLoader.loadClass(Unknown Source)
at sun.misc.Launcher$AppClassLoader.loadClass(Unknown Source)
at java.lang.ClassLoader.loadClass(Unknown Source)
at org.junit.internal.runners.model.EachTestNotifier.addFailure(EachTestNotifier.java:23)
at org.junit.runners.ParentRunner.run(ParentRunner.java:242)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:49)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)

I tried commenting out the NonStrictExpectations block and the Verifications block, and I get the same error.

The NPE is thrown from a call to currentThread()... which I have no Idea how it could fail.

Any ideas?


Solution

  • It turns out the problem that that the root superclass of Daemon is java.lang.Thread, which caused JMockit to have trouble. The solution was static partial mocking of the methods required by the test.

    public class DaemonTest {
    
    @Test
    public void testExecute(final ConfigHelper ch, final DaemonHelper dh) {
    
    new NonStrictExpectations(d) {
        @Mocked({"log"}
        Daemon d;
        @Mocked({"()"})
        DaemonHelper dh;
        {
    
        }
    };
    
    
    final Config c = new Config(ch);
    final Daemon d = new Daemon(c, dh);
    d.execute();
    
    new Verifications() {{
        d.log("Starting");
        d.log("Ending");
    }};
    }
    }