I'm trying to capture a parameter passed in input to a mock object with PowerMockito, this is the code:
//I create a mock object
ClassMocked mock = PowerMockito.mock(ClassMocked.class);
//Create the captor that will capture the String passed in input to the mock object
ArgumentCaptor<String> argumentCaptor = ArgumentCaptor.forClass(String.class);
//When the method put is executed on my mock I want the second parameter (that is a String) to be captured
Mockito.verify(mock).put(anyString(), inputDataMapCaptor.capture());
//Creates the instance of the class that I want to test passing the mock as parameter
ClassToTest instance = new ClassToTest(mock);
//Executes the method that I want to test
instance.methodToTest();
/* I know that during the execution of "methodToTest()" mock.put(String,String) will be executed and I want to get the second string parameter. */
When I execute the test I have an exception executing the line Mockito.verify(mock).put(...);
"Wanted but not invoked mock.put(any,Capturing argument);"
What is wrong?
You should call instance.methodToTest(); before Mockito.verify(mock).put(anyString(), inputDataMapCaptor.capture());
verify() verifies that the specified method call did take place.
You can't verify "upfront" that a method call is supposed to happen.
Thus: verify() needs to happen after the facts, not before!
Related
I have a bunch of objects in a List<MyClass> myObjects, which should be used as parameters of a method call on a mocked object. I'd like to verify that the corresponding method is called exactly once for each instance in myObjects like
Iterator<MyClass> it = myObjects.iterator();
while(it.hasNext()) {
MyClass myCurrentObj = it.next();
Mockito.verify(myMock).add(myCurrentObj); //fail here:
}
With this code, I get informed that my call was not done, but other interactions on the mock happened. This is not the case if I use Matchers.any(MyClass.class). Might be because the method calls on the mock don't have the same order than the corresponding parameters.
How can I verify that the method was called once for each entry in myObjects?
One way would be to use an ArgumentCaptor to collect all the values with which your mock was invoked:
final int nrElements = myObjects.size();
final ArgumentCaptor<MyClass> captor = ArgumentCaptor.forClass(MyClass.class);
verify(theMock, times(nrElements)).add(captor.capture());
// This is using assertJ
assertThat(captor.getAllValues()).isEqualTo(myObjects);
A side effect is that this will also check invocation order since the captor will add captured values in order.
Here is a part of my method that i want to test:
protected void myMethod(MyObject o) {
o.setComment("comment");
MyObjectDAO.updateMyObject(o);
}
Here is a part of my JUnit:
#Mock
private MyObjectDAO myObjectDaoMock;
#Test
public void testMyMethod() {
MyObject o = new MyObject();
// Run Test
x.myMethod(o);
// Control
assertEquals("comment", o.getComment());
verify(myObjectDaoMock).updateMyObject(o);
}
The test is green; we are now testing whether the comment attribute of myObject is set, and the update method is called with myObject. But not whether the update method is called with the updated attribute (after setComment method). When we change the position of two lines in myMethod (first updating the object, then setting its attribute), our test is still green.
I thought that the ArgumentCaptor can be useful here. So i made this one:
#Mock
private MyObjectDAO myObjectDaoMock;
#Test
public void testMyMethod() {
MyObject o = new MyObject();
// Run Test
x.myMethod(o);
// Control
ArgumentCaptor<MyObject> argumentCaptor = ArgumentCaptor.forClass(MyObject.class);
verify(myObjectDaoMock).updateMyObject(argumentCaptor.capture());
MyObject oActual = argumentCaptor.getValue();
assertEquals("comment", oActual.getComment());
}
... hoping that the ArgumentCaptor will capture that state of the object, by which the update method is called, so i can be sure that the update method is called with the updated comment attribute. The test is green again. But it still does not test cleverly. When we change the position of two lines in myMethod again (first updating the object, then setting its attribute), our test is still green.
I understand that, the ArgumentCaptor does not create another attribute for himself (argumentCaptor.getValue()), it is the reference of the original object. So since java works with Reference by Value, for JUnit it does not make any difference whether i update the object before or after, as long as the objectIds are same.
How can i actually test that the updateObject method is called with the updated value of myObject?
EDIT: Another idea was (thanks to #Crazyjavahacking) to mock also myObject (although i don't want that), and define a call-order with 2 mocks:
InOrder inOrder = inOrder(o, myObjectDAOMock);
inOrder.verify(o).setComment("comment");
inOrder.verify(myObjectDAOMock).updateMyObject(o);
That still does not test that the method is called with the updated value. It just test the order. When we change our code:
o.setComment("comment");
o.setComment("comment2");
MyObjectDAO.updateMyObject(o);
.. our test would still run green, since the order is correct based on our order definition. But the method is not called with the updated value "comment" as we want.
It is behaving differently because you are mixing 2 concepts:
mocking
assertions
The only way to do what you need is to have mocked both MyObject and MyObjectDAO. In that case you can verify whether the setter was called on MyObject and also the order of calls. In Mockit use the
InOrder inOrder = inOrder(o, myObjectDAOMock);
inOrder.verify(o).setComment("...");
// 1.) inOrder.verify(o, times(0)).setComment(anyString());
inOrder.verify(myObjectDAOMock).updateMyObject(o);
// 2.) assertEquals(o.getComment(), "comment");
// 3.) verifyNoMoreInteractions(o);
construction.
Couple of notes:
this will guaranteed there are no more other invocations to setComment()
if we will use #Spy for MyObject instead of #Mock, we can verify what is the final value of the comment in MyObject instance
this will guarantee no other invocation is performed on the passed instance
How can I capture (for assertion purposes) the parmeters passed to a static stub method call?
The methodBeingStubbed looks like this...
public class SomeStaticClass{
protected static String methodBeingStubbed(Properties props){
...
I am stubbing the method call because it i need to verify that it gets called...
PowerMockito.stub(PowerMockito.method(SomeStaticClass.class, "methodBeingStubbed")).toReturn(null);
PowerMockito.verifyStatic();
But I now also want to know what properties were passed to this "methodBeingStubbed" and assert it is as expected
After the call to verifyStatic, you'll need to actually call the method you're trying to verify, as in the documentation here:
PowerMockito.verifyStatic(Static.class);
Static.thirdStaticMethod(Mockito.anyInt());
At that point you can use Mockito argument captors, as demonstrated (but not tested):
ArgumentCaptor<Properties> propertiesCaptor =
ArgumentCaptor.forClass(Properties.class);
PowerMockito.verifyStatic(SomeStaticClass.class);
SomeStaticClass.methodBeingStubbed(propertiesCaptor.capture());
Properties passedInValue = propertiesCaptor.getValue();
If you're used to #Mock annotations, or you need to capture a generic (as in List<String>), you may also be interested in using the #Captor annotation instead.
I would like to verify if a parameter of a mocked object is correctly mapped (before the methodcall there is a mapping).
I've created two objects, one of which has the expected values.
I expect the false one to fail, but somehow easymock does not verify if the parameter contains the expected values. How can I fix that?
Real class does:
public SomeObject methodname() {
MyClass parameter = mapper.map(source,Dest.class);
serviceBeingMocked.doSomething(parameter); //<-- want to verify this parameter
}
Test
MyClass correct = ...;
correct.setA=a;
correct.setB=b;
expect(serviceBeingMocked(correct)).andReturn(iDontCare); //this should work
MyClass false = ...;
false.setA=eeeeeeeeeee;
false.setB=ffffffffff;
expect(serviceBeingMocked(false)).andReturn(iDontCare); // this test should fail
Thanks in advance!
Edit: Found the answer (using capture to record the paramter and test the values via assert)
Capture paramter = new Capitre();
expect(serviceBeingMocked(EasyMock.capture(parameter)));
assertEquals(parameter.getValue().getWhatever().equals(correct.getWhatever());
If I understand correctly, this test is a test foe methodname(). And you would like to test that, given a source, the correct MyClass paremeter is created by the mapper, and passed to serviceBeingMocked.doSomething().
So in fact, your unit test for methodname() actually tests the mapper.map() method. That's wrong. You should write a unit test for mapper.map() to test that. Once you've ensured that mapper.map() works as expected, you can test methodname() by mocking the mapper.map() method, and verify that the result of this mocked method is passed to the mocked service (although this test wouldn't add much value).
To be complete, if you really want to go your way and check the value passed to serviceBeingMocked(), then you should use a capture.
I'm telling mock object to wait for method with command:
mockObject.registerSQLDriver(isA(SomeName.class));
At runtime method is called exactly with instance of SomeName class, but the test fails telling that "Unexpected method call registerSQLDriver()"
What can cause this problem?
Here is the code:
resetToDefault(_SQLDriverManager);
_SQLDriverManager.registerSQLDriver(isA(SQLDriver.class));
expectLastCall().anyTimes();
replay(_SQLDriverManager);
Probably, you are mocking one instance and testing another instance.
To check this you should add a name parameter in the mock creation:
Comparable<String> mock01 = EasyMock.createMock("M1", Comparable.class);
Comparable<String> mock02 = EasyMock.createMock("M2", Comparable.class);
EasyMock.expect(mock01.compareTo(EasyMock.isA(String.class))).andReturn(1);
EasyMock.replay(mock01, mock02);
mock02.compareTo("Test");
EasyMock.verify(mock01, mock02);
In this case the test will fail with the message:
Unexpected method call M2.compareTo("Test")
instead of:
Unexpected method call Comparable.compareTo("Test")