
mockito - issue #127
Not able to mock package-protected methods when running in OSGi
Take this two line example:
MyMock mock = Mockito.mock(MyConcreteClass.class); when(mock.packageLocalMethod()).thenReturn("foo");
In the 2nd line, the package local method is actually called! It is as if I just wrote:
mock.packageLocalMethod()
I would expect one of to things in this case:
1) Support mocking of package local methods, or 2) throw an exception when trying to mock a package local method.
ps. I guess I'm not on the 1.8 release. I'm on 1.8 rc2. If you think this is fixed in 1.8 let me know and I'll try to upgrade.
Best, Evan
Comment #1
Posted on Oct 6, 2009 by Quick BearA better title might have been "Support stubbing of package local methods, or throw exception on attempt"
Comment #2
Posted on Oct 7, 2009 by Massive MonkeyInteresting - it should work fine. Can you please: 1. check if the method is not final 2. tell me what version of Mockito do you use
Comment #3
Posted on Oct 7, 2009 by Quick Bear- The method definitely is not final.
- I'm currently using 1.8 rc2.
Comment #4
Posted on Oct 7, 2009 by Massive MonkeyHi, I'm not sure I understand the problem. Mockito should deal with default-visible methods easily. There are many tests that prove it :) For example try this:
static class Foo {
String foo() {
return null;
}
}
@Test
public void shouldAllowMockingDefaultVisibleMethods() {
Foo mock = mock(Foo.class);
when(mock.foo()).thenReturn("foo");
assertEquals("foo", mock.foo());
verify(mock).foo();
}
So:
In the 2nd line, the package local method is actually called!
This is true, it is actually called but it does not mean you cannot mock 'default access' methods.
Comment #5
Posted on Oct 8, 2009 by Quick BearHmm. In my case since the actual method is called, the test fails right there. The class being mocked would require some complex dependencies to be injected for the method to work, so when the actual method is called it NPEs. Seems odd that I would have to code my methods so they could be called without effect under a certain conditions. Why is the actual method called as opposed to the mock's "blank" method?
Comment #6
Posted on Oct 8, 2009 by Massive MonkeyIf the 'real' method is called then - either the method is final (so it cannot be mocked and real behavior is called) - or you're doing spy() instead of mock() - or you have stubbed your mock to call real method (e.g. thenCallRealMethod())
For the regular mocks, e.g. Foo foo = mock(Foo.class), the implementation of methods is irrelevant as mocked behavior is empty - no NPEs can be thrown.
It might be useful if you narrow down your test case and paste it into this bug report
Comment #7
Posted on Oct 12, 2009 by Quick BearHmm seems I couldn't reproduce it in a simple test case. It sounds like its some kind of edge case I hit. Could it be that the class I'm mocking is in the same package but in a different jar than the test class?
Comment #8
Posted on Oct 12, 2009 by Massive Monkeyhmmmm... in theory this could be related to the signed / unsigned packages. Can I somehow get hold of the jar?
You can also try mocking with a different mocking framework and tell me if it worked or not.
Good luck!
Comment #9
Posted on Oct 20, 2009 by Massive MonkeyOk, closing for now. Let me know if you find anything more about it.
Comment #10
Posted on Mar 1, 2011 by Happy LionI observe the same behavior when trying to mock in an OSGi environment.
I'll try to give you some context information. Maybe this may help find the real problem. We have some Unit Tests that are started both a) directly as JUnit Tests in Eclipse (Run as JUnit...) and b) in a running (Equinox) OSGi environment.
In case a) mocking works for public and for package private methods of our classes. In case b) package private methods are not mocked. Public methods are mocked in both cases, so there does not seem to be a general problem with classloading.
Could you please reopen the issue?
Comment #11
Posted on Mar 1, 2011 by Massive Monkey(No comment was entered for this change.)
Comment #12
Posted on May 30, 2012 by Massive ElephantI also experience this problem trying to mock classes from AWT, but only in java 1.7. I'm using Mockito 1.9.0.
Should I open a different bug, given that this doesn't seem to be only OSGI?
Here's some test code to reproduce the problem:
@Test
public void shouldNotNullPointer() {
class MyPanel extends JPanel {
MyPanel(Component aComponent) {
add(aComponent);
}
}
final JCheckBox myBox = mock(JCheckBox.class);
assertNotNull(new MyPanel(myBox));
}
On the Component class, setGraphicsConfiguration is calling the real method.
Comment #13
Posted on Aug 17, 2012 by Helpful BirdI have also run into this problem on 1.8.5. I have two jars, one with my real code and one with my tests. When trying to stub package protected methods the real implementation is called.
Also, on a plain mock (no stubbing) calling one of the package protected methods from the test results in null being returned, as expected. However, when calling the same package protected method from the real code, the real method implementation is called. More details about the code can be seen in this SO post: http://stackoverflow.com/questions/11996809/
Comment #14
Posted on Aug 17, 2012 by Happy Lion@Comment 12
I think you got things mixed up.
In your example you create a real MyPanel instance. And in its constructor you call its real add() method.
A quick test for mocking AWT classes works fine:
JPanel jPanel = mock(JPanel.class); jPanel.add(new JCheckBox()); // No exception
Comment #15
Posted on Aug 17, 2012 by Massive MonkeyThe last chapter on code.google.com/p/google-guice/wiki/OSGi explains the way OSGi uses classloaders. This impacts the definition of "package-private" in the OSGi environment. So this is not a Mockito bug, but it may be something that the Mockito team would want to consider finding a workaround for.
Comment #16
Posted on Aug 19, 2012 by Massive Elephant@Comment 14
If you look at the implementation of the add method, it calls back and forth between the parent and child components. The error happens when the parent (MyPanel) tries to call a method on the child (myBox) which is package-protected and calls the real method instead of being mocked.
Comment #17
Posted on Aug 20, 2012 by Happy HorseHi, I agree with David there.
Unfortunately we are not OSGi experts, if you think you can help on this matter, it would be very welcome. Typically having a zip file with an OSGI project showing the issue, or also how to create an OSGI envoronment where we can reproduce this.
Cheers, Brice
Comment #18
Posted on Dec 12, 2012 by Massive BearHi, I have the same issue easyly reproducable. here is the tested class. public class Foo { public Integer getPublicInt() { return 2; } protected Integer getIntProtectedMethod() { return 2; } Integer getIntPackageProtectedMethod() { return 2; } } here is the test class placed in the same package of course. public class TestFoo { @Test public void testPublicMethod() { Foo fooSpy = Mockito.spy(new Foo()); Mockito.doReturn(Integer.valueOf(3)).when(fooSpy).getPublicInt(); assertEquals(Integer.valueOf(3), fooSpy.getPublicInt()); } @Test public void testProtectedMethod() { Foo fooSpy = Mockito.spy(new Foo()); Mockito.doReturn(Integer.valueOf(3)).when(fooSpy).getIntProtectedMethod(); assertEquals(Integer.valueOf(3), fooSpy.getIntProtectedMethod()); } @Test public void testPackageProtectedMethod() { Foo fooSpy = Mockito.spy(new Foo()); Mockito.doReturn(Integer.valueOf(3)).when(fooSpy).getIntPackageProtectedMethod(); assertEquals(Integer.valueOf(3), fooSpy.getIntPackageProtectedMethod()); } }
the third test fails when launched in a OSGI context. If you use eclipse just create a plugin with these classes in it with dependencies on Junit and Mockito bundles and use the "JUnit Plugin Test" lauch configuration.
Comment #19
Posted on Dec 12, 2012 by Massive Bearhere is attached a zip with 3 eclipse projects 1) org.mockito.test.method.visibility, with the test case and the launch configuration to launch the test 2) junit plugin 3) mockito plugin just launch the "Test Mockito mock with visibility methods as plugins" and you should see the third method fail.
Comment #20
Posted on Dec 12, 2012 by Happy HorseHi thanks,
We will take a look, but don't except something asap, we are currently all pretty busy on other matter, though if you have a proposal on how to fix this we could make it work in the master.
Regards, Brice
Comment #21
Posted on Jan 29, 2013 by Helpful Elephant@Comment 12 I've created a separate issue for this (http://code.google.com/p/mockito/issues/detail?id=416) because that problem is not related to OSGi.
Comment #22
Posted on Jul 18, 2014 by Helpful WombatNote, there is a subtle difference when using fragments. Although fragments share the same class loader with their host bundle, there is something different. Unfortunately, I haven't found the place yet where I read about it. But I'm investigating this to see if there is a solution possible in CGLIB.
Comment #23
Posted on Sep 19, 2014 by Helpful MonkeySee https://github.com/mockito/mockito/pull/82 for a way to reproduce the issue. It's not just OSGi which is affected but also environments where the class/interface to mock is in a different jar than the class defining the mock.
Status: New
Labels:
Type-Defect
Priority-Medium