SS Holmes
SS Holmes

Reputation: 11

PowerMockito - testing methods invoked by constructor

I am trying to write tests for legacy code. One of the classes I am trying to test is a constructor. This constructor itself invokes several other methods.

I am trying to write a unit test for this constructor to verify that the methods invoked by the constructor are indeed invoked.

I am using PowerMock 1.5.5 and Mockito 1.9.5 with Test NG with eclipse (org.testng.eclipse - 6.8.6.20141201_2240) on eclipse Luna Release (4.4.0).

Could I please ask for guidance on what I am doing wrong? I get the exception:

Wanted but not invoked: classWithConstructor.doSomethingWithS(); -> at com.example.constructortester.MakerOfClassWithConstructorTest.testSomething(MakerOfClassWithConstructorTest.java:30) Actually, there were zero interactions with this mock.

I expected that doSomethingWithS should have been invoked, but the error message I get tells me that the Mock itself is not used, and therefore the method I expected to be invoked on the spy can never be invoked.

Below are the code snippets:

The legacy class that has the constructor, which in turns calls another method

package com.example.constructortester;

public class ClassWithConstructor {

    public static final String MODIFIED = "Modified:";

    public ClassWithConstructor(String s) {
        String returnVal = doSomethingWithS(s);
        System.out.println("ClassWithConstructor::ClassWithConstructor - :"
                + returnVal);
    }

    protected String doSomethingWithS(String s) {
        System.out
                .println("ClassWithConstructor::doSomethingWithS - Something with s:"
                        + s);
        return MODIFIED + s;
    }
}

My class that I use as a builder:

package com.example.constructortester;

public class MakerOfClassWithConstructor {

    public MakerOfClassWithConstructor() {
    }

    public void doSomething(String s) {
        new ClassWithConstructor(s);
    }
}

Finally, the TestNG test:

package com.example.constructortester;

import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import static org.testng.Assert.assertEquals;

import org.mockito.Mockito;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.testng.PowerMockTestCase;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;

@PrepareForTest(MakerOfClassWithConstructor.class)
public class MakerOfClassWithConstructorTest extends PowerMockTestCase {

    @Test
    public void testSomething() throws Exception {
        final String someString = "Test";
        final String someOtherString = "SomeOtherTest";

        ClassWithConstructor spyClassWithConstructor = spy(new ClassWithConstructor(
                someString));
        PowerMockito.whenNew(ClassWithConstructor.class)
                .withArguments(someString).thenReturn(spyClassWithConstructor);

        PowerMockito.doReturn(someOtherString).when(spyClassWithConstructor)
                .doSomethingWithS(someString);
        // PowerMockito.when(spyClassWithConstructor.doSomethingWithS(someString))
        // .thenReturn(someOtherString);

        new MakerOfClassWithConstructor().doSomething(someString);

        // This works
        PowerMockito.verifyNew(ClassWithConstructor.class).withArguments(
                someString);

        // This fails with error:
        // Wanted but not invoked:
        // classWithConstructor.doSomethingWithS(<any>);
        // -> at
        // com.example.constructortester.MakerOfClassWithConstructorTest.testSomething(MakerOfClassWithConstructorTest.java:30)
        // Actually, there were zero interactions with this mock.
        Mockito.verify(spyClassWithConstructor, times(1)).doSomethingWithS(
                someOtherString);
    }
}

Upvotes: 1

Views: 2799

Answers (2)

Paulo Gon&#231;alo
Paulo Gon&#231;alo

Reputation: 121

This is a Java bug.

Try to add -noverify in the VM arguments of the test launcher. Or (the best solution) update the JDK. Mine was 1.7.0_u67 and I updated it to version 1.7.0_u79 and worked (even without the -noverify).

Upvotes: 2

Vikas Madhusudana
Vikas Madhusudana

Reputation: 1482

you have to call the method using the mock object before verifying it so you should add a line

spyClassWithConstructor.doSomethingWithS(someOtherString);

before

 Mockito.verify(spyClassWithConstructor, times(1)).doSomethingWithS(
            someOtherString);

In your case it is not going to verify(skipping it) because you have not even called the method, Verification can be done only after you call the method

Upvotes: 0

Related Questions