简体   繁体   中英

Mocking Local Scope Objects using Powermock and mockito within a static method

This question has probably been asked a lot of times before. However, I couldn't find answers anywhere. I'm dealing with legacy code here.

Please Note : I'm simplifying my question to get a very specific answer. The code snippets only represent the problem I'm facing. Not the actual code I'm trying to test. The code snippet to be tested here represents part of the overall code I need to test.

Problem : myObj.loadContent(null,null) is actually being called instead of doing nothing as specified with PowerMockito.doNothing().when(mockObj).loadContent(null, null);

Code I wish to unit test :

class ClassInstantiatingObject {
.
.
    public static void doSomething(Arg1 arg1, Arg2 arg2) throws Exception{
        MyClass myObj = new MyClass(arg1, arg2);
        myObj.loadContent(null, null);
    }
}

My Unit Test :

import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mockito;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
.
.
.
@Test
public void testDoSomething() throws Exception {
    MyClass mockObj = PowerMockito.mock(MyClass.class);
    PowerMockito.whenNew(MyClass.class).withAnyArguments().thenReturn(mockObj);
    PowerMockito.doNothing().when(mockObj).loadContent(null, null);
    Arg1 mockArg1 = mock(Arg1.class);
    Arg2 mockArg2 = mock(Arg2.class);
    StaticClass.doSomething(mockArg1, mockArg2);
}

The code to be tested cannot be changed. Hence, I need a way to actually not call loadContent(null,null) using mockito/powermock.

Also, when using : PowerMockito.doNothing().when(MyClass.class,"loadContent",null,null) OR PowerMockito.doNothing().when(MyClass.class,"loadContent",Mockito.anyString(),Mockito.anyMap())

I get a java.lang.NullPointerException at org.powermock.api.mockito.internal.expectation.PowerMockitoStubberImpl.addAnswersForStubbing

CORRECT ANSWER

I've managed to figure out the solution. It's very simple to be honest.

In the example specified above. What I was missing was, in case of using PowerMockito.whenNew() , the class that is calling the constructor you wish to mock must be specified in the annotation @PrepareForTest. The class whose constructor you wish to mock need not be specified at all.

For eg.

import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mockito;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;

@RunWith(PowerMockRunner.class)

//Only need to declare the class calling the constructor to use 
//PowerMockito.whenNew(). You do not need to declare the class whose mock 
//you plan on returning in case of the constructor call.
//In this case, no need to mention MyClass.class in PrepareForTest

@PrepareForTest({ClassInstantiatingObject.class})
public class ClassInstantiatingObjectTest
{
.
.
.
    @Test
    public void testDoSomething() throws Exception {
        MyClass mockObj = PowerMockito.mock(MyClass.class);
        PowerMockito.whenNew(MyClass.class).withAnyArguments().thenReturn(mockObj);

        //Only way to do nothing via Powermock for a local scope object
        //whose method call returns void

        //PowerMockito.doNothing().when(mockObj.loadContent(null,null)); 
        //will cause a compile time exception

        PowerMockito.doNothing().when(mockObj,"loadContent",null,null);
        Arg1 mockArg1 = mock(Arg1.class);
        Arg2 mockArg2 = mock(Arg2.class);
        StaticClass.doSomething(mockArg1, mockArg2);
    }
}

The ^above code will be the solution.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM