Dave
Dave

Reputation: 19150

How do I mock any arguments to a private method using PowerMockito?

I’m using Mockito 1.9.5, PowerMock 1.5.1, JUnit 4.11, and Spring 3.1.4.RELEASE. I’m trying to write a JUnit test in which I want to mock a private method doing nothing. The private method signature is

public class MyService
{

    …
    private void myMethod(byte[] data, UserFile userFile, User user)
    {

And in my JUnit test I have

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration({ "classpath:test-context.xml" })
@PrepareForTest(MyServiceImpl.class)
public class MyServiceIT 
{

    @Rule
    public PowerMockRule rule = new PowerMockRule();

    @Autowired
    private MyService m_mySvc;
    private MyService m_mySvcSpy;

    @Before
    public final void setup() throws Exception
    {
        m_mySvcSpy = PowerMockito.spy(m_mySvc);
        PowerMockito.doNothing().when(m_mySvcSpy, “myMethod”, Matchers.any(byte[].class), Matchers.any(UserFile.class), Matchers.any(User.class));

Unfortunately, the second line dies with the exception

testUploadFile(org.mainco.subco.user.service.MyServiceIT)  Time elapsed: 12.693 sec  <<< ERROR!

org.powermock.reflect.exceptions.MethodNotFoundException: No method found with name ‘myMethod’ with parameter types: [ null, null, null ] in class org.mainco.subco.user.service.UserFileService$$EnhancerByMockitoWithCGLIB$$4e52bc77. at org.powermock.reflect.internal.WhiteboxImpl.throwExceptionIfMethodWasNotFound(WhiteboxImpl.java:1247) at org.powermock.reflect.internal.WhiteboxImpl.findMethodOrThrowException(WhiteboxImpl.java:985) at org.powermock.reflect.internal.WhiteboxImpl.doInvokeMethod(WhiteboxImpl.java:882) at org.powermock.reflect.internal.WhiteboxImpl.invokeMethod(WhiteboxImpl.java:713) at org.powermock.reflect.Whitebox.invokeMethod(Whitebox.java:401) at org.powermock.api.mockito.internal.expectation.PowerMockitoStubberImpl.when(PowerMockitoStubberImpl.java:93) at org.mainco.subco.user.service.MyServiceIT.setup(UserFileServiceIT.java:42)

What is the right way to mock generic arguments for a private method using PowerMockito?

Upvotes: 3

Views: 15240

Answers (6)

Narasimha
Narasimha

Reputation: 41

In my case I wanted the private method to "return" something, so this is what I did

        MyTestClass spyInstance = spy(MyTestClass.getNewInstance());
        MyGenericClass obj = mock(MyGenericClass.class);

           doReturn(obj).when(spyInstance,method(MyTestClass.class,"privateMethod",
            String.class,HashMap.class,Class.class)).
            withArguments("624",null,MyGenericClass.class);`

where my private method is ...

private <T> T privateMethod(String str,HashMap<String,String> map,Class<T> c)

Upvotes: 1

Dave
Dave

Reputation: 19150

I went ahead and used "suppress" ...

suppress(method(MyServiceImpl.class,  “myMethod”));

Upvotes: 1

XoXo
XoXo

Reputation: 1599

Since you are seeing this exception:

org.powermock.reflect.exceptions.MethodNotFoundException: No method found with name ‘myMethod’ with parameter types: [ null, null, null ] in class

Can you try using mockito's isNull matcher (and probably with some type-casting)?

In other words, you use instead

PowerMockito.doNothing().when(m_mySvcSpy, "myMethod", Matchers.isNull(byte[].class), Matchers.isNull(UserFile.class), Matchers.isNull(User.class));

Btw, you can static import Matchers.isNull so that you can simply use isNull instead of Matchers.isNull

Upvotes: 0

gontard
gontard

Reputation: 29520

I guess that your test is annotated with SpringJUnit4ClassRunner. In this case you have to use the PowerMockRule:

public class MyServiceTest {
    @Rule
    public PowerMockRule rule = new PowerMockRule();
    ...

Moreover your are stubbing a method of MyService with powermock. So you must annotate the test class with @PrepareForTest:

...
@PrepareForTest(MyServiceImpl.class)
public class MyServiceTest {
    ...

Complete code:

@PrepareForTest(MyServiceImpl.class)
@RunWith(SpringJUnit4ClassRunner.class)
public class MyServiceTest {
    @Rule
    public PowerMockRule rule = new PowerMockRule();

    @Autowired
    private MyService service;
    private MyService spy;

    @Before
    public final void setup() throws Exception {
        spy = PowerMockito.spy(service);
        PowerMockito.doNothing().when(spy,
                "myMethod",
                Matchers.any(byte[].class),
                Matchers.any(UserFile.class),
                Matchers.any(User.class));
    }

    ...
}

You could see a full example of spying in the documentation.

Upvotes: 0

Rog&#233;rio
Rog&#233;rio

Reputation: 16380

I haven't tested it, but I believe the reason the private method isn't found is that it doesn't exist in the object provided by Spring for the MyService interface. This object is a proxy , an instance of a generated class which does not extend MyServiceImpl; so, there is no private myMethod(...) in it.

To avoid the problem, the test should simply not use Spring. Instead, instantiate MyServiceImpl directly in the setup() method. If the test needs other dependencies to get injected into m_mySvc, then create mocks for those and let PowerMock inject them.

Upvotes: 1

Tomas Aschan
Tomas Aschan

Reputation: 60574

The premise for your question seems to imply that you're violating the Single Responsibility Principle (SRP); if you need to test the private method, and to do that you need to inject stuff into it, you should probably consider moving it out to a different service.

I suggest that you do the following:

public class MyService implements IService { // I know it's not a strong convention in
                                             // the Java world, but I'm primarily a C#
                                             // guy, so I tend to give any interface a
                                             // name that starts with captital "I"

    public MyService(IDependencyOne dep1, IDependencyTwo dep2) {
        // ...
    }

    public Stuff getTheStuffThatAnIServiceGets() {
        // your previously private method was used here before
        // Now, it's instead a method defined on the IDependencyTwo interface,
        // so you have it available as _dep2.myMethod(...)
    }
}

public class OtherService implements IDependencyTwo {
    public void myMethod(/* possibly some arguments... */) {
        // ...
    }
}

With this separation, you can inject something that mocks the behavior of the previously private method (just mock IDependencyTwo) when you're testing MyService, and similarly you can mock whatever you need to inject into the previously private method by mocking and injecting the dependencies of IDependencyTwo.

Upvotes: 0

Related Questions