I have written a unit test using JMock 2.6.0-RC2 that makes use of several package private classes. For some reason, this causes an IllegalAccessError
:
java.lang.IllegalAccessError: tried to access class foo.PackagePrivateClass from class $Proxy6
at $Proxy6.getInstance(Unknown Source)
at foo.UsingClass.<init>(UsingClass.java:6)
at foo.FailingTest.testFailure(FailingTest.java:29)
I have uploaded a minimal Maven project that demonstrates the issue to here: http://dl.dropbox.com/u/108474287/example-project.zip. The relevant code is also shown below (it's fairly concise).
Why am I seeing an error in my test? The test class is part of the same package as the tested classes, so I would not expect access control to be an issue.
Some interesting observations:
If I change ExampleInterface
to be package private (rather than public), the problem goes away. Sadly, in my real-life project this is not a possibility.
The exception only occurs if I return a value from my mock object. Those who download my example project will see another test in which null
is returned; this test passes.
If I move the all the classes into the default package, the tests pass! If all the classes remain in package foo
, the tests fail.
Below are the files contained in my project. The ZIP I linked to above is a small Maven project that houses all of these.
I have also posted this question to the JMock developer list. I will update this question if I receives answers there (and vice versa).
FailingTest.java
package foo;
// Imports omitted
@RunWith(JMock.class)
public class FailingTest {
private static final PackagePrivateClass EXAMPLE_INSTANCE =
new PackagePrivateClass();
public Mockery context = new JUnit4Mockery();
@Test
public void testFailure() {
final ExampleInterface exampleInterface = context
.mock(ExampleInterface.class);
context.checking(new Expectations() {
{
oneOf(exampleInterface).getInstance();
will(returnValue(EXAMPLE_INSTANCE));
}
});
new UsingClass(exampleInterface); <-- exception thrown from constructor
}
}
ExampleInterface.java
package foo;
public interface ExampleInterface {
PackagePrivateClass getInstance();
}
PackagePrivateClass.java
package foo;
class PackagePrivateClass {
PackagePrivateClass() {}
@Override
public String toString() {
return "Hello, World!";
}
}
UsingClass.java
package foo;
class UsingClass {
UsingClass(ExampleInterface exampleInterface) {
PackagePrivateClass bar = exampleInterface.getInstance(); // <--- exception
System.out.println(bar); // originates here
}
}