Hot questions for Using Mockito in eclipse

Question:

I have an Eclipse RCP Project with multiple plugins. I am writing plain JUnit tests (no dependencies to Eclipse/UI) as separate fragments to the plugin-under-test.

When using Mockito and trying to mock an interface from another plugin (which is exported correctly; I can use the interface in my code), I get a SecurityException related to class signing:

org.mockito.exceptions.base.MockitoException: 
Mockito cannot mock this class: interface ch.sbb.polar.client.communication.inf.service.IUserService
Mockito can only mock visible & non-final classes.
If you're not sure why you're getting this error, please report to the mailing list.
at org.mockito.internal.runners.JUnit45AndHigherRunnerImpl$1.withBefores(JUnit45AndHigherRunnerImpl.java:27)

[...]

Caused by: org.mockito.cglib.core.CodeGenerationException: java.lang.reflect.InvocationTargetException-->null
at org.mockito.cglib.core.AbstractClassGenerator.create(AbstractClassGenerator.java:238)

[...]

Caused by: java.lang.reflect.InvocationTargetException
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)

[...]

Caused by: java.lang.SecurityException: Signers of 'ch.sbb.polar.client.communication.inf.service.IUserService$$EnhancerByMockitoWithCGLIB$$a8bfe723' do not match signers of other classes in package

at java.lang.ClassLoader.checkPackageSigners(ClassLoader.java:361)

at java.lang.ClassLoader.defineClass(ClassLoader.java:295)

... 40 more

When I run the tests as "JUnit Plugin tests", i.e. with an OSGi environment, everything works as expected. But I'd like to use the plain JUnit execution because of speed; in the class under test, I don't need the OSGi environment.

Does anybody know a way to do that?


Answer:

As is mentioned in the comments, the root cause is that the Eclipse Orbit package of Mockito (which I had added to my target platform) is signed, and because of a bug in the underlying CGLIB, you cannot mock unsigned classes/interfaces with a signed Mockito.

See https://code.google.com/p/mockito/issues/detail?id=393 for the most detailed description. The bug is fixed in CGLIB head, but has not yet appeared in a release. Mockito only uses released versions as dependencies, so the fix is not yet in Mockito, with an unknown (to me) timeline, as when this will be in.

Workaround: Provide unsigned Mockito in separate bundle

The workaround is to package the Mockito JAR (and its dependencies) in its own bundle and export the necessary API packages.

When using Maven Tycho, JUnit, Hamcrest, and Mockito, the only way I was able to make this work and resolve all dependency / classpath / classloader issues correctly was the following way:

  • Create Maven module with the following entries in the pom.xml:

    <packaging>eclipse-plugin</packaging>
    

    [...]

    <dependencies>
      <dependency>
        <groupId>org.mockito</groupId>
        <artifactId>mockito-core</artifactId>
        <version>1.10.19</version>
      </dependency>
    </dependencies>
    

    [...]

    <plugin>
      <groupId>org.apache.maven.plugins</groupId>
      <artifactId>maven-dependency-plugin</artifactId>
      <executions>
        <execution>
          <id>copy-test-libs</id>
          <goals>
            <goal>copy-dependencies</goal>
          </goals>
          <configuration>
            <outputDirectory>lib</outputDirectory>
            <stripVersion>true</stripVersion>
            <includeScope>runtime</includeScope>
          </configuration>
        </execution>
      </executions>
    </plugin>
    
  • Use following entries in the MANIFEST.MF:

    Bundle-ClassPath: lib/mockito-core.jar,
     lib/objenesis.jar
    Export-Package: org.mockito,
     org.mockito.runners
    Require-Bundle: org.junit;bundle-version="4.11.0";visibility:=reexport,
     org.hamcrest.library;bundle-version="1.3.0";visibility:=reexport,
     org.hamcrest.core;bundle-version="1.3.0";visibility:=reexport
    
  • And finally in your unit test fragment, add this new bundle as a dependency.

Question:

Consider you want to mock an interface using Mockito containing the following method signatures:

public void doThis(Object o);

public void doThis(Object... o)

I need to verify that doThis(Object o) (and not the other method) has been invoked exactly one time.

First I thought that the following line would do the trick:

verify(mock, times(1)).doThis(anyObject());

However, as this seems to work on Windows, it doesn't on Linux because in this environment, a call to of the other doThis method is expected. This is caused because the anyObject() argument seems to match both method signatures and one is chosen in a more or less unpredictable way.

How can I enforce that Mockito always chooses doThis(Object o) for verification?


Answer:

This is not a mockito issue.

During further investigating, I realized that the actual method is chosen at compile-time (JLS ยง15.12.2). So basically the class files differed between windows and linux which caused different mockito behavior.

The interface is discouraged (see Effective Java, 2nd Edition, Item 42). I changed it to match the following:

public void doThis(Object o);

public void doThis(Object firstObj, Object... others)

With this change the expected (first) method will always be chosen.

One thing is still left: Why does the java compiler on windows (eclipse compiler) produce a different output than Oracle JDK javac on Linux?

This might be a bug in ECJ because I would expect that the java language spec is pretty strict here.

Question:

I recently added Mockito to a maven project on eclipse, by adding the external jar "mockito-core-2.0.53-beta.jar", and upon attempting to create my first mock object (Line two in the function)

And upon running it, the console prints out the first line, then throws this error:

It seems like previously there was a similar issue, but it was supposedly fixed internally. https://github.com/raphw/byte-buddy/issues/99

What is going wrong here?


Answer:

You simply forgot to add the dependencies to your project which are according to the pom file:

<dependency>
  <groupId>net.bytebuddy</groupId>
  <artifactId>byte-buddy</artifactId>
  <version>1.3.16</version>
  <scope>runtime</scope>
</dependency>
<dependency>
  <groupId>org.objenesis</groupId>
  <artifactId>objenesis</artifactId>
  <version>2.1</version>
  <scope>runtime</scope>
</dependency>

In other words you need to add byte-buddy 1.3.16 and objenesis 2.1 to your project too.

More details here

Question:

I have the following, heavily simplified class:

public class MyClass
{
    private MqttClient field;

    public void test() throws MqttException
    {
        field = new MqttClient(null, null);
        field.connect();
    }
}

I am using Eclipse Paho's MqttClient class.

I want to test the test method with a UnitTest. In order to have control over the MqttClient instance I want to mock the object. My test-class looks as follows:

public class TestMyClass
{
    // Make sure we are running with the PowerMockAgent initialized
    static
    {
        PowerMockAgent.initializeIfNeeded();
    }

    // Make sure we are using PowerMock
    @Rule
    public PowerMockRule    rule    = new PowerMockRule();

    // Mocked MqttClient
    @Mock
    MqttClient              field;

    // MyClass-Object injected with mocks.
    @InjectMocks
    MyClass                 myClass = new MyClass();

    @PrepareForTest(MyClass.class)
    @Test
    public void test() throws Exception
    {
        // Initialize our mocks from annotations
        MockitoAnnotations.initMocks(this);

        // Catch the "new MqttClient(null, null);"
        PowerMockito.whenNew(MqttClient.class).withAnyArguments().thenReturn(field);


        myClass.test();

    }
}

When I execute my test I am met with the following error:

java.lang.NullPointerException
    at test.java.test.MyClass.test(MyClass.java:13)
    at test.java.test.TestMyClass.test(TestMyClass.java:45)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:47)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:44)
    at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
    at org.powermock.modules.junit4.rule.PowerMockStatement.evaluate(PowerMockRule.java:73)
    at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:271)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:70)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:238)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:63)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:236)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:53)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:229)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:309)
    at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:86)
    at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:538)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:760)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:460)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:206)

I can call any method on field it is always a null-reference. My problem is I have no idea why this is the case.

I changed the type of field to several other classes, including java.awt.point and SerializationInstantiatorHelper (in order to test if it has to do with MqttClient being an external dependency) as well as several classes in my project, calling an appropriate method on those objects. In all those cases the problem did not exist and the test succeeded without any issues. The method on the mocked object is called and does nothing - just as I want it to.

Only when using the MqttClient class this problem occurs. Or at least I did not find any other class yet to reproduce this problem.

I am in all honesty totally lost at this point. What makes the MqttClient class special? Why can I seemingly not mock it like any other class? What did I miss?

//EDIT

I narrowed down the problem by creating a local version of MqttClient, copying over the source code. In all honesty, I am even more confused now though. The class has three constructors with the following signatures:

1.)

public MqttClient(  String serverURI,
                    String clientId) throws MqttException

2.)

public MqttClient(  String serverURI,
                    String clientId,
                    MqttClientPersistence persistence) throws MqttException

3.)

public MqttClient(  String serverURI,
                    String clientId,
                    MqttClientPersistence persistence,
                    ScheduledExecutorService executorService) throws MqttException

If one of those three constructors is removed, everything works. Any combination of the class with two of those three constructors is working just fine. As soon as all three constructors exist, the beforementioned error message appears. This leads me to the assumption it could have something to do with PowerMockito not finding the correct constructor? If so, how would that be avoidable?


Answer:

The mocked target appears to have not been configured correctly so it is not behaving as expected when exercising the test.

Sometimes keeping things simple (KISS) is the way to go.

@RunWith(PowerMockRunner.class)
@PrepareForTest(MyClass.class)
public class TestMyClass {

    @Test
    public void test() throws Exception {
        //Arrange

        // mock MqttClient
        MqttClient field = mock(MqttClient.class);
        // setup the "new MqttClient(null, null);"
        PowerMockito.whenNew(MqttClient.class).withArguments(isNull(), isNull()).thenReturn(field);

        MyClass subject = new MyClass();

        //Act
        subject.test();

        //Assert
        PowerMockito.verifyNew(MqttClient.class).withArguments(isNull(), isNull());
        verify(field).connect();
    }
}

By using .withArguments with the appropriate arguments or matchers, it helps narrow down specifically which constructor is to be mocked for the test, avoiding any conflicts when multiple constructors exists.

Based on the simplified class under test shown in the example, there are no dependencies being injected as it initialized the dependency locally (i.e: tight coupling), so there really was no need to inject mocks into the class under test.

Also PrepareForTest is usually done on the test class and not the test method in this case, as according to documentation

All usages require @RunWith(PowerMockRunner.class) and @PrepareForTest annotated at class level.

emphasis mine

Question:

This fails with InitializationError. Other tests in the same package run so I have done something silly in my code. Stacktrace reads "No tests found matching [[Exactmatch]]".

public class TestClassToTest {
    @Mock
    File mockOfAFile;

    @Test
    public void testAMethod(File mockOfAFile) {
        MockitoAnnotations.initMocks(this);
        given(fileMock.getName()).willReturn("test1");
        assertEquals("test1",ClassBeingTested.methodBeingTested(mockOfAFile));
    }
}

Have tried everything but am very new to Mockito. What silly thing am I doing here ?

Thanks


Answer:

I found two things to fix:

  1. The @Test method should have no parameters
  2. You need another File instance, called fileMock.

So here is the updated code:

public class TestClassToTest {

    @Mock
    File mockOfAFile;

    @Mock
    File fileMock; // the new mock

    @Test
    public void testAMethod() { // no parameters
        MockitoAnnotations.initMocks(this);
        given(fileMock.getName()).willReturn("test1"); // here is the new mock used
        assertEquals("test1",ClassBeingTested.methodBeingTested(mockOfAFile));
    }
}

Question:

I've been given a bunch of tests to develop a simple game and I've reached a point where Mockito's InOrder.verify() produces the error.

Verification in order failure. Wanted but not invoked: jumpListener.jumpPerformed( ... ) at line x. Wanted anywhere AFTER the following interaction: walkListener.walkPerformed( ... ) at line y.

The code I got looks similar to what is seen below where the relevant functions performWalk(int x) and performJump(int y) both contains other function calls in if / else logic, before and after walkListeners.get(0).walkPerformed(x); and jumpListeners.get(0).jumpPerformed(y);. I've never heard about Mockito until reaching this part and most questions seems to be asked by those producing the tests, not using them. So my question is, what exactly does inOrder.verify() require of the function calls?

order.verify(walkListener).walkPerformed(5);
order.verify(jumpListener).jumpPerformed(2);

Can there be other function calls going off between these two statements, say a boolean function checking the argument value interval?

public interface WalkListener extends EventListener {
    public void walkPerformed(int x);
}

public interface JumpListener extends EventListener {
    public void jumpPerformed(int y);
}

public class Game {
    private Vector<WalkListener> walkListeners;
    private Vector<JumpListener> jumpListeners;

    public void addWalkListener(WalkListener listener) { ... }
    public void addJumpListener(JumpListener listener) { ... }

    public void performWalk(int x) {   
        ... 
        walkListeners.get(0).walkPerformed(x);
        ...
    }
    public void performJump(int y) { 
        ...      
        jumpListeners.get(0).jumpPerformed(y);
        ... 
    }

    private class Walk implements WalkListener { ... }
    private class Jump implements JumpListener { ... }
}

public class GameTest {
    @Test
    public void finalTest() {
        Game game = new Game();
        WalkListener walkListener = mock(WalkListener.class)
        JumpListener jumpListener = mock(JumpListener.class)

        game.addWalkListener(walkListener);
        game.addJumpListener(jumpListener);

        game.performWalk(5);
        game.performJump(2);

        InOrder order = inOrder(walkListener, jumpListener);
        order.verify(walkListener).walkPerformed(5);
        order.verify(jumpListener).jumpPerformed(2);
    }
}

Answer:

So this is the relevant bit:

InOrder order = inOrder(walkListener, jumpListener);
order.verify(walkListener).walkPerformed(5);
order.verify(jumpListener).jumpPerformed(2);

It verifies that

  1. jumpListener is called after walkListener (the case you're failing, since you apparently don't call jumpListener at all),
  2. walkListener.walkPerformed() is called with argument 5 and
  3. jumpListener.jumpPerformed() is called with argument 2

Can there be other function calls going off between these two statements, say a boolean function checking the argument value interval?

Sure.

See example:

class Foo {
    public void foo() {}
    public void bar() {}
    public void baz() {}
}

@Test
public void testFoo() {

    Foo mock = mock(Foo.class);
    mock.foo(); //1st
    mock.bar(); //2nd
    mock.baz(); //3rd

    InOrder inOrder = inOrder(mock);

    inOrder.verify(mock).foo(); //1st
    inOrder.verify(mock).baz(); //3rd (last method)

    //passes because there are no more interactions after last method:
    inOrder.verifyNoMoreInteractions();

}

Test passes, as after baz() call there were no more method calls. It doesn't matter that bar() call was in between as that was not part of verification.

Same is the case with two classes:

class Foo {
    public void foo() {}
    public void bar() {}
}

class Bar {
    public void foo() {}
}

@Test
public void testFoo() {

    Foo mock = mock(Foo.class);
    Bar mock2 = mock(Bar.class);
    mock.foo(); //1st
    mock.bar(); //2nd
    mock2.foo(); //3rd

    InOrder inOrder = inOrder(mock, mock2);

    inOrder.verify(mock).foo(); //1st
    inOrder.verify(mock2).foo(); //3rd (last method)

    //passes because there are no more interactions after last method:
    inOrder.verifyNoMoreInteractions();
}

Test again passes, as the second method call was not part of verification.

If you'd have wanted the test to fail on non-specified methods calls, you'd need to add for example Mockito.verifyNoMoreInteractions(mock); at the end of the test.

Question:

I am trying to use Mockito to do some verifications about the number of times a method was called, but the syntax that I'm seeing in all the tutorials I can find is causing an "Unresolved compilation problem" error in eclipse. The class I'm mocking is:

public class ClassToBeMocked {
    public void methodToVerify(String input) {

    }
}

The test is:

@RunWith(MockitoJUnitRunner.class)
public class MockitoTest {
    @Mock ClassToBeMocked mockedClass;

    @Before
    public void setUp() throws Exception {
        this.mockedClass = Mockito.mock(ClassToBeMocked.class);
    }

    @Test
    public void test() {
        Mockito.verify(mockedClass, Mockito.never()).methodToVerify();
    }
}

But when I try to run the test in eclipse, I get this error:

java.lang.Error: Unresolved compilation problem: 
The method methodToVerify(String) in the type ClassToBeMocked is not applicable for the arguments ()

at MockitoTest.test(MockitoTest.java:28)
at . . . 

At first blush, the error seems logical: after all, it appears as though I am calling a method without passing in the required parameters. But I thought Mockito would do some under-the-hood work to make it work.

If my use of the framework is wrong, then how should I be verifying this method?

I'm using Mockito version 2.7.6. I have not tried running the test outside of eclipse because I'm new to java/junit/mockito/maven, and I haven't yet figured out how to run the tests from the terminal.


Answer:

You'll need to include an argument matcher, e.g. anyString():

Mockito.verify(mockedClass, Mockito.never()).methodToVerify(Mockito.anyString());