Reputation: 395
I don't have much experience with Mocking, I have recently started using it in my Junit test cases. However, I am having difficulties understanding the execution.
I am getting IllegalArgumentException when I try this code
PowerMockito.doNothing().when(spyObject, "lockUser", String.class, User.class);
But when I provide the values that the lockUser would recieve at the time of execution, everything works as expected.
Working code
PowerMockito.doNothing().when(spyObject, "lockUser", "my_text", userMock);
I am rather confused with this behavior. I was expecting identical behaviour. Could someone explain why this is happening ?
In addition when I have the following code
PowerMockito.doNothing().when(spyObject, "lockUser", anyString(), anyObject());
The method is no longer mocked and the real method is invoked.
Interestingly I have another method with same name "lockUser" which takes different number of parameters. And in my other test method, I have used only Matchers (anyObject(), anyString() etc) and that works as expected.
PowerMockito.doNothing().when(spyObject, "lockUser", anyObject(), anyString(), anyString(), anyString());
All lockUser methods are priavate.
I am working with Mockito 1.9.5 together with PowerMock 1.5.6
Any help is greatly appreciated
Edit Additional Code to make it clear
Class Core {
public Worker getWorker(String workerId) {
// Get worker from Map<String, Worker> fID_WRK with workerId as key
// Get user from worker (I have mocked this part, so my mock user is
// returned)
If(user.isTooOld()) {
lockUserAndNotify(reason, user);
throw new UserLockedException("Too old");
}
private void lockUserAndNotify(String reason, User user) {
lockUserAndNotify(reason, user.fname, user.lname); // locks user and notifies
}
public getUser(String login, String password) {
// find user in database
if(user password is too old) {
lockUserAndNotify(dbConnection, fname, lname, userId);
}
}
private lockUserAndNotify(Connection dbConn, String fName, String lName, String
userId) {
//method call to lock the user
//method call to notify the admin
}
}
My Test class
Class CoreTest {
@Test (expected = UserLockedException.class)
public void getUser_ThrowsException() throws
Exception{
Core core = new Core();
Core coreSpy = PowerMockito.spy(core);
when(userMock.isPwdUpdateTimeExpired()).thenReturn(true);
PowerMockito.doNothing().when(coreSpy, "lockUserAndNotify",
anyObject(), anyString(), anyString(), anyString(), anyString());
admin4.UserManager.getUser("l.user1","password");
}
@Test (expected = UserLockedException.class)
public void getWorker_ThrowsException() throws
Exception{
Core core = new Core();
Core coreSpy = PowerMockito.spy(core);
Map workerMap = Whitebox.getInternalState(coreSpy, "fID_WRK");
Map workerMapSpy = PowerMockito.spy(workerMap);
when(workerMapSpy.getWorker("12345")).thenReturn(workerMock);
when(workerMock.getUser()).thenReturn(userMock);
when(userMock.isTooOld()).thenReturn(true);
PowerMockito.doNothing().when(coreSpy, "lockUserAndNotify",
anyString(), anyObject());
admin4.UserManager.getWorker("123445");
}
}
So the test getUser_ThrowsException works as expected, but getWorker_ThrowsException does not.
Upvotes: 2
Views: 4357
Reputation: 9385
To answer the part of your question about IllegalArgumentException: argument type mismatch
, you get this because you're using the API incorrectly when you use
PowerMockito.doNothing().when(spyObject, "lockUser", String.class, User.class);
See the documentation of PowerMocktioStubber.when, relevant section reproduced here -
public static <T> org.mockito.stubbing.OngoingStubbing<T> when(Class<?> klass,
Object... arguments)
throws Exception
Expect calls to private static methods without having to specify the method name. The method will be looked up using the parameter types if possible
Throws:
Exception - If something unexpected goes wrong.
See Also:
Mockito#when(Object)}
As you've already observed you can use either the values of the real parameters or your can use Matchers
like anyString
.
Here's some sample code to demonstrate this -
public class Core {
public String getWorker(String workerId) {
if (workerId.isEmpty()) {
lockUser("Reason", workerId);
}
return workerId;
}
private void lockUser(String reason, String user) {
}
}
and the corresponding tests -
@RunWith(PowerMockRunner.class)
@PrepareForTest(Core.class)
public class CoreTest {
@Test
// this is incorrect usage and throws an IllegalArgumentException
public void test1() throws Exception {
Core spy = PowerMockito.spy(new Core());
PowerMockito.doNothing().when(spy, "lockUser", String.class, String.class);
spy.getWorker("");
}
@Test
public void test2() throws Exception {
Core spy = PowerMockito.spy(new Core());
PowerMockito.doNothing().when(spy, "lockUser", Mockito.anyString(), Mockito.anyString());
spy.getWorker("");
PowerMockito.verifyPrivate(spy).invoke("lockUser", Mockito.anyString(), Mockito.anyString());
}
@Test
public void test3() throws Exception {
Core spy = PowerMockito.spy(new Core());
PowerMockito.doNothing().when(spy, "lockUser", "abc", "Reason");
spy.getWorker("abc");
PowerMockito.verifyPrivate(spy, Mockito.times(0)).invoke("lockUser", Mockito.anyString(), Mockito.anyString());
}
}
Without compilable code or the exception that you get for getWorker_ThrowsException
, it's not possible to answer why that doesn't work as expected. I can take a look again once you add the required information.
Upvotes: 2