Reputation: 19150
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
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
Reputation: 19150
I went ahead and used "suppress" ...
suppress(method(MyServiceImpl.class, “myMethod”));
Upvotes: 1
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
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
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
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