Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Mock all instances of a class

I know this is typically a bad practice but in my case it is necessary.

I have a case where an Enum holds a class to gain some information. So that Enum creates an instance of that calss in its Constructor.

public enum MyEnum {
    CONSTANT(new MyImpl());

    private final MyImpl myImpl;

    private MyEnum(final MyImpl impl) {
        this.myImpl = impl;
    }

    public void sayHello() {
        System.out.println(this.myImpl.getSomethingToSay());
    }

}

MyImpl.java is just a class with a single method that returns a String.

public class MyImpl {

    public String getSomethingToSay() {
        return "Hello!";
    }

}

Now finally the unit test:

import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mockito;
import org.mockito.runners.MockitoJUnitRunner;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.testng.PowerMockTestCase;

@RunWith(MockitoJUnitRunner.class)
@PrepareForTest({ MyImpl.class, MyEnum.class })
public class MyEnumTest extends PowerMockTestCase {
    @Test
    public void testSmth2() throws Exception {
        MyImpl impl = Mockito.mock(MyImpl.class);
        Mockito.when(impl.getSomethingToSay()).thenReturn("It works!");
        PowerMockito.whenNew(MyImpl.class).withAnyArguments().thenReturn(impl);

        System.out.println(impl.getSomethingToSay());
        System.out.println(new MyImpl().getSomethingToSay());
        MyEnum.CONSTANT.sayHello();
    }
}

The output is:

It works!
Hello!
Hello!

But should be 3 times it works!

like image 526
Zarathustra Avatar asked Dec 27 '13 08:12

Zarathustra


People also ask

What is a mock instance?

Instance mocking means that a statement like: $obj = new \MyNamespace\Foo; …will actually generate a mock object. This is done by replacing the real class with an instance mock (similar to an alias mock), as with mocking public methods.

Can we mock the object of class?

We can use Mockito class mock() method to create a mock object of a given class or interface. This is the simplest way to mock an object. We are using JUnit 5 to write test cases in conjunction with Mockito to mock objects.

What is the difference between Powermock and Mockito?

While Mockito can help with test case writing, there are certain things it cannot do viz:. mocking or testing private, final or static methods. That is where, PowerMockito comes to the rescue. PowerMockito is capable of testing private, final or static methods as it makes use of Java Reflection API.

Can we mock method of same class?

We can mock runInGround(String location) method inside the PersonTest class as shown below. Instead of using mock(class) here we need to use Mockito. spy() to mock the same class we are testing. Then we can mock the method we want as follows.


1 Answers

I found the faulty part.

I changed

@RunWith(MockitoJUnitRunner.class)

to

@RunWith(PowerMockRunner.class)

Now the mocking works. But i have to say that as Jon Skeet printed out, the enum does not have everywhere that mocked member-instance. So in another Unit test calling MyEnum.CONSTANT.sayHello(); will print again it works instead of Hello!.

like image 65
Zarathustra Avatar answered Oct 14 '22 18:10

Zarathustra