I was writing a Junit to test a scenario where an object changes its variables and saves it into the database 2 times. The argumentCaptor is invoked in save operation. The getAllValues() is returning two records. But both values are referenced to the same last capture record.
ImplimentationClass.java
...
myObj.setVariable(oneValue);
saveMyObj(myObj);
myObj.setVariable(otherValue);
saveMyObj(myObj);
...
saveMyObj(MyObject myObj){
repository.save(myObj);
}
ImplimentationClassTest.java
private ImplimentationClass underTest ;
#Mock
private Repository mockRepository;
#Before
public void setup(){
initMocks(this);
underTest = new ImplimentationClassTest();
}
#Test
public void test(){
ArgumentCaptor<MyObject> captor = ArgumentCaptor.forClass(MyObject.class);
MyObject obj = new MyObject(value);
underTest.implementedMethod(obj);
verify(mockRepository, times(2)).save(captor.capture());
assertEquals(oneValue, captor.getAllValues().get(0).getVariable()); //failing here -getting otherValue
assertEquals(otherValue, captor.getAllValues().get(1).getVariable());
}
Any idea how to capture same object multiple times?
The problem from your test originates from this piece of code.
myObj.setVariable(oneValue);
saveMyObj(myObj);
myObj.setVariable(otherValue);
saveMyObj(myObj);
Once you change the variable inside of myObj you change it for all references. Note that the ArgumentCaptor does not make a deep copy of myObj.
So you will end up with two references to myObj, which only has the latest state.
To avoid this you might want to pass a different instance to the second call.
Another alternative might be to use doAnswer instead and check the correctness of the paramter inside that method.
Check this answer for an example.
Related
Hello I am fairly new to unit testing with Junit as well as Mockito. I think I have a fairly reasonable understanding of the principles but I can't seem to find any explanations of what I am specifically trying to test online.
I want to test a method, that calls several other methods (void and non-void), which also instantiates objects in the method body. I unfortunately cannot share the code as it is not mine, but here is a general format:
class classToTest {
private final field_1;
public void methodToTest( string id, List object_1, List object_2) {
try {
Map<SomeObject_1, SomeObject_2> sampleMap = new HashMap<>();
method_1(object_1, object_2); //void function modifies object_2
field_1.method_2(id, object_2);
Map<SomObeject_1, List<object>> groupedList = groupList(object_2)
//Then some stuff is added to the sampleMap
}
//catch would be here
}
At the moment I only care about testing method_1, and I cannot test directly as it is a private method so I must go through this parent method call. I wish I could change the code but I have been asked to keep it the same and to test in this manner with Mockito and Junit.
I know I need to Mock an object of the class to Test as well as its parameter:
private classToTest classToTestObject;
#Mock private field_1 f1;
#Before
public void setup() {
MockitoAnnotations.init.Mocks(this);
classToTestObject = mock(classToTest.class, CALLS_REAL_METHODS);
}
but I don't know where to start my actual test, as in how I can essentially just execute that one method call and ignore all the rest. I can't just not ignore the other objects and method calls either as the main method will throw exceptions if they are not handled correctly.
Any help and guidance is much appreciated, sorry that I could not share the code. Thank You!
At the moment I only care about testing method_1, and I cannot test directly as it is a private method so I must go through this parent method call.
Per your comment, and the note in your code:
method_1(object_1, object_2); //void function modifies object_2
You would set up a test that allows you to verify the expected final state of object_2. You would do this with a real instance of the class, not a mock.
#Test
public void method1Test() {
// Assemble - your preconditions
ClassToTest subject = new ClassToTest();
List<SomeType> object_1 = new ArrayList();
List<SomeOtherType> object_2 = new ArrayList();
// Populate object_1 and object_2 with data to use as input
// that won't throw exceptions. Call any methods on subject that put
// it in the desired state
// Act - call the method that calls the method under test
subject.methodToTest("some id that makes the method run correctly", object_1, object_2);
// Assert - one or more assertions against the expected final state of object_2
assertThat(object_2).matchesYourExpectations();
}
I have a JUnit test as:
#Spy
ParallelSender parallelSender = new ParallelSender();
#Test
public void send() {
// making some data...
parallelSender.send(someData);
// check that internal method has been called with Sender Task made from someData
verify(parallelSender).doSend(any(SenderTask.class));
}
I however like to examine that SenderTask contains all the fields exactly as I need them. Can I tell the spy to intercept the doSend call, store its parameters in some array and then continue to real method?
Use the ArgumentCaptor:
#Test
public void send() {
// making some data...
parallelSender.send(someData);
// Define the captor for class
ArgumentCaptor<SenderTask> captor =
ArgumentCaptor.forClass(SenderTask.class);
// Capture input while verifying
verify(parallelSender).doSend(captor.capture());
// Assert
SomeTask result = captor.getValue();
// assertions on result
}
You can use an ArgumentCaptor.
#Captor
ArgumentCaptor<SenderTask> captor;
// or ArgumentCaptor<SenderTask> captor =
// ArgumentCaptor.forClass(SenderTask.class);
#Test public void send() {
// ...
verify(parallelSender).doSend(captor.capture());
SenderTask captured = captor.getValue();
I rarely use argument captor because it's usually not necessary.
Just do this
#Test
public void send() {
//given
SomeData myInput = ...
SenderTask expectedOutput = new SenderTask();
expectedOutput.setSomeField(/*expected field value*/);
//when
parallelSender.send(myInput);
//then
verify(parallelSender).doSend(expectedOutput);
}
The idea behind is to check that "doSend" was called with an expected object.
Note: just make sure that you implemented equals/hash method in SenderTask - or it will not work
Note2: I would suggest avoiding using any() in your unit tests. Usually when your are unit-testing something - you want to be as much precise as possible. So use concrete objects during results verification.
Hopefully it helps
I'm trying to test the following method
public void saveToMultipleSources(MyObject myObject)
{
if (myObject.isOfSomeType()) {
firstDAO.saveObject(myObject);
myObject.setContent(null);
}
secondDAO.saveObject(myObject);
}
The test I wrote was
#Test
public void testSaveFeature()
{
//initialize all objects
obj.saveToMultipleSources(myObject); //myObject has a valid content.
Mockito.verify(firstDAO).saveObject(myObject);
myObject.setContent(null);
Mockito.verify(secondDAO).saveObject(myObject);
}
But on running, I get the error that expected and actual arguments differ for the verify statement of firstDAO. The expected was an object with valid content but actual arguments invoked are with Content set as null. I tried the exact same thing with ArgumentCaptor as well, but got the same results.
Can someone explain why does Mockito behave this way? I tried logging the entire object and can see valid Content being set just before I call the firstDAO.
Also how do I go about testing this?
//initialize all objects
obj.saveToMultipleSources(myObject); //myObject has a valid content.
Mockito.verify(firstDAO).saveObject(myObject);
The problem is that setting the objects content to null is a side effect of your method. In consequence Mockito compares the recorded parameter (having valid content) with the object modified by your method (having content already set to null).
In that case, how can I test this? – Abhilash Panigrahi
In the test Make myObject a Mockito.spy() and prevent the execution of setContent():
#Test
public void testSaveFeature()
{
//initialize all objects
MyObject spyOfMyObject = Mockito.spy(myObject);
doNothing().when(spyOfMyObject).setContent(null); // special null matcher may be needed...
obj.saveToMultipleSources(spyOfMyObject);
Mockito.verify(firstDAO).saveObject(spyOfMyObject);
Mockito.verify(spyOfMyObject).setContent(null);
Mockito.verify(secondDAO).saveObject(spyOfMyObject);
}
But you most likely want to be sure that myObject.setContent(null);
is called before econdDAO.saveObject(myObject);`...
#Test
public void testSaveFeature()
{
//initialize all objects
MyObject spyOfMyObject = Mockito.spy(myObject);
doNothing().when(spyOfMyObject).setContent(null);
obj.saveToMultipleSources(spyOfMyObject);
Mockito.verify(firstDAO).saveObject(spyOfMyObject);
InOrder inOrder = Mockito.inOrder(spyOfMyObject,secondDAO);
inOrder.verify(spyOfMyObject).setContent(null);
inOrder..verify(secondDAO).saveObject(spyOfMyObject);
}
I have following code preparing mocks to test my service using Cassandra (I need to mock com.datastax.driver.core.ColumnDefinitions.Definition) :
#RunWith(PowerMockRunner.class)
public class TestMyClass{
private MyClass target;
#Before
public void setUp() throws Exception {
ColumnDefinitions mockColumnDefinitions=Mockito.mock(ColumnDefinitions.class);
Mockito.when(mockRow.getColumnDefinitions()).thenReturn(mockColumnDefinitions);
target= new MyClass();
Definition mockDef = Mockito.mock(Definition.class);
List<Definition> defList = new ArrayList<Definition>();
defList.add(mockDef);
Iterator mockIterator = Mockito.mock(Iterator.class);
Mockito.when(mockColumnDefinitions.iterator()).thenReturn(mockIterator);
Mockito.when(mockIterator.hasNext()).thenReturn(true, false);
Mockito.when(mockIterator.next()).thenReturn(mockDef);
Mockito.when(mockDef.getName()).thenReturn(NAME);
}
#Test
public void testMyMethod() throws Exception {
target.MyMethod();
}
}
Test execution goes fine this place, and I have this type of code in different places, so it should work.
Inside the service I am testing I have following code:
ColumnDefinitions colDef = row.getColumnDefinitions();
Iterator<Definition> defIterator = colDef.iterator();
while (defIterator.hasNext()) {
Definition def = defIterator.next();
String columnName = def.getName();
}
When I debug this code, I see, that both colDef and defIterator are mocked successfully. I see something like that in debug variables area:
Mock for Iterator, hashCode: 430126690
But after defIterator.next() invocation I see that though def is an object and not null, it doesn't show hashcode like for Iterator, instead I see this:
com.sun.jdi.InvocationException occurred invoking method.
And after invoking this string:
String columnName = def.getName();
I immediately get NullPointerException like if def is null.
What am I doing wrong?
Thanks.
EDIT 1 ________________________________________________________________________
I also tried to use PowerMockito with the same methods instead, the result is the same.
EDIT 2 ________________________________________________________________________
I added the whole test method code.
It is been a while since this question was created. I have faced this same problem few days ago and I have solved it in the following manner (I hope my proposed solution helps someone in the future):
First of all, I want to clarify that ColumnDefinition.Definition class is a public static nested class that has four private final fields and only has one constructor: Definition (String keyspace, String table, String name and DataType type) (for more details please refer to the ColumnDefinitions.Definition javadoc and ColumnDefinitions source code). Therefore this nested class could not be mocked by Mockito nor Powermock because of its final fields.
SOLUTION:
I had to create a real object, not a mocked one of the class ColumnDefinition.Definition using reflection, so you can initialise the mockDef object as follows:
Constructor<Definition> constructor = (Constructor<Definition>) Definition.class.getDeclaredConstructors()[0]; // as Definition only has one constructor, 0 will be passed as index
constructor.setAccessible(true);
Definition mockDef = constructor.newInstance("keyspace", "table", "name", null);
replacing this line of code in your snippet:
Definition mockDef = Mockito.mock(Definition.class);
Then the NullPointerException will never be thrown again when executing this line of code:
String columnName = def.getName();
I'm trying to implement Mockito to test a particular method but the .thenReturn(...) seems to always be returning a null object instead of what I intended:
CUT:
public class TestClassFacade {
// injected via Spring
private InterfaceBP bpService;
public void setBpService(InterfaceBP bpService) {
this.bpService = bpService;
}
public TestVO getTestData(String testString) throws Exception {
BPRequestVO bpRequestVO = new BPRequestVO();
bpRequestVO.setGroupNumber(testString) ;
bpRequestVO.setProductType("ALL") ;
bpRequestVO.setProfileType("Required - TEST") ;
IBPServiceResponse serviceResponse = bpService.getProduct(bpRequestVO); //PROBLEM
if (serviceResponse.getMessage().equalsIgnoreCase("BOB")) {
throw new Exception();
} else {
TestVO testVO = new TestVO();
}
return testVO;
}
}
Spring Configuration:
<bean id="testClass" class="com.foo.TestClassFacade">
<property name="bpService" ref="bpService" />
</bean>
<bean id="bpService" class="class.cloud.BPService" />
Mockito Test Method:
#RunWith(MockitoJUnitRunner.class)
public class BaseTest {
#Mock BPService mockBPService;
#InjectMocks TestClassFacade mockTestClassFacade;
private String testString = null;
private BPRequestVO someBPRequestVO = new BPRequestVO();
private IBPServiceResponse invalidServiceResponse = new BPServiceResponse();
#Test (expected = Exception.class)
public void getBPData_bobStatusCode_shouldThrowException() throws Exception {
invalidServiceResponse.setMessage("BOB");
someBPRequestVO.setGroupNumber(null);
someBPRequestVO.setProductType("ALL");
someBPRequestVO.setProfileType("Required - TEST");
System.out.println("1: " + someBPRequestVO.getGroupNumber());
System.out.println("2: " + someBPRequestVO.getProductType());
System.out.println("3: " + someBPRequestVO.getProfileType());
System.out.println("4: " + someBPRequestVO.getEffectiveDate());
when(mockBPService.getProduct(someBPRequestVO)).thenReturn(invalidServiceResponse);
mockTestClassFacade.getTestData(testString);
verify(mockBPService).getProduct(someBPRequestVO);
}
}
System output:
1: null
2: ALL
3: Required - TEST
4: null
What's happening here is that when I run the test the serviceResponse object is null on the line in the CUT marked with //PROBLEM above. My desire is to have that object be populated with my "invalidServiceResponse" object from my test method. Judging from the output of my System.out.println's it appears that my bpRequestVO matches my someBPRequestVO in content.
Could some one show me what I'm missing here?
Thanks for your time!
Instead of creating a equals method in your BPRequestVO class you can create a mock argument with "any(YourObject.class)" like this:
when(mockBPService.getProduct(any(BPRequestVO.class))).thenReturn(invalidServiceResponse);
The instance of BPRequestVO that you use with when() is different than the one used in getTestData().
Unless you override equals(), they will not match.
You should not need to write a custom Matcher if you override equals(). Note the following from the Mockito documentation:
"Custom argument matchers can make the test less readable. Sometimes it's better to implement equals() for arguments that are passed to mocks (Mockito naturally uses equals() for argument matching). This can make the test cleaner."
The problem is in your usage of when().
You submit a reference to a constructed instance; as a result, the mocking will return what you want only if the argument passed to the method is the same reference.
What you want is an argument matcher; something like:
when(mockBPService.getProduct(argThatMatches(someBPRequestVO))
.thenReturn(whatYouWant);
Of course, it requires that you write the argument matcher!
Note that there is a builtin matcher which can do what you want:
when(mockBPService.getProduct(eq(someBPRequestVO))).thenReturn(whatYouWant);
This matcher of course requires that your BPRequestVO class implements equals() (and hashCode() too)!
My problem was that mocked services were defined as final.
The BPRequestVO Object instance used for mocking is different than Instance used while junit execution.
The best way is to configure any instance of the object while mocking
when(mockBPService.getProduct(someBPRequestVO)).thenReturn(invalidServiceResponse);
Can be updated with
when(mockBPService.getProduct(Mockito.any(BPRequestVO.class))).thenReturn(invalidServiceResponse);
My issue was passing null as method arguments doesn't match the when() clause I set up.
e.g.
Car car = mock(Car.class)
when(car.start(anyString()).thenReturn("vroom");
assertEquals("vroom", car.start(null));
This would fail.
assertEquals("vroom", car.start("Now"));
This passes.
My issue was with the instance of the service which is autowired/mockbean had different instance at the Test->given() part and whi lein the execution it had different instance.
This was found by running the test in debug mode and checking each value in the mock stub and execution code. If all the parameters and the mocked instance are same then only the thenReturn() will return the expected value.
In myscenario the mocked instance of the class had multiple implementations and by adding #Qualifier("name") the instance became same in the given() and real execution.
it may also happened in multi-thread case. the mocked object's handler been reset by mockito after the return of #Test method while somewhere(another Thread) still using the mocked object.
as for the situation Thread provided by a pool, you can mock a thread pool instead, executing the Runner.run() in current Thread is proved effective.