Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Mocking a class object using Mockito and PowerMockito

Is it possible to mock a class object using Mockito and/or PowerMockito?

Something like:

Class<Runnable> mockRunnableClass = mock(Class<Runnable>.class);
like image 557
LandonSchropp Avatar asked Aug 29 '12 00:08

LandonSchropp


People also ask

Can I mock objects in Mockito?

The Mockito. mock() method allows us to create a mock object of a class or an interface. We can then use the mock to stub return values for its methods and verify if they were called. We don't need to do anything else to this method before we can use it.

How do you mock a class object in Java?

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 Mockito and PowerMockito?

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.


2 Answers

First, as stated in the comments, you would need to do:

Class<Runnable> mockRunnableaClass = (Class<Runnable>)mock(Class.class);

But that won't work in the usual way because of a limitation with PowerMock. You cannot simply mock classes in from java.lang, java.net, java.io or other system classes because they're loaded by Java's bootstrap classloader and cannot be byte-code manipulated by PowerMock's classloader. (See PowerMock FAQ #4.) As of PowerMock 1.2.5, you can work around this. If the class you wanted to test was this:

public class ClassToTest {
  private Class<Runnable> runnableClass;

  public void setRunnableClass(Class<Runnable> runnableClass) {
    this.runnableClass = runnableClass;
  }

  public Runnable foo() {
    return runnableClass.newInstance();
  }
}

Then you would do this:

@RunWith(PowerMockRunner.class)
@PrepareForTest({ ClassToTest.class }) // Prepare the calling class for test
public class SystemClassUserTest {

  @Test
  public void testFoo() throws Exception {
    Class<Runnable> mockClass = (Class<Runnable>) mock(Class.class);
    Runnable mockRunnable = mock(Runnable.class);

    ClassToTest objectUT = new ClassToTest();
    objectUT.setRunnableClass(mockClass);

    when(mockClass.newInstance()).thenReturn(mockRunnable);
    assertThat(objectUT.foo(), is(sameInstance(mockRunnable);
  }
}
like image 92
jhericks Avatar answered Nov 15 '22 13:11

jhericks


why not using an agent if you can't refactor the code there isn't many options, as @jherics mentionned, java system classes are loaded by the bootstrap classloader and powermock can't redefine their bytecode.

However Powermock now coms with an agent, that will allow system classes mock. Check here for complete explanation.

The main idea is to modify your java command and add :

-javaagent: path/to/powermock-module-javaagent-1.4.12.jar

The basic thing this agent is doing is to definalize classes, to allow future mocking in a specific test, that's why you'll need to use specific types to communicate with the agent, for example with JUnit :

@Rule PowerMockRule rule = new PowerMockRule(); // found in the junit4 rule agent jar

TestNG is also supported. Just check the wiki page for more information.

Hope that helps.

like image 32
Brice Avatar answered Nov 15 '22 14:11

Brice