How to create an argument captor for Map<String, SomeCustomClass>
?
I have the code that follows the following pattern:
import java.util.HashMap;
import java.util.Map;
public class CompoundClass {
public CompoundClass (String a, String b){
this.a = a;
this.b = b;
}
public String a;
public String b;
}
public class SubClass {
public void doSomeThingSubClass(Map<String, CompoundClass> mapSb) {
...
}
}
public class Example {
public SubClass sb;
public Example(SubClass sb) {
this.sb = sb;
}
public void doSomeThing () {
Map<String, CompoundClass> mapSb = new HashMap<>();
mapSb.put("x", new CompoundClass("aa","bb"));
sb.doSomeThingSubClass(mapSb);
}
}
And I want to test if the method doSomethingSubClass(mapSb)
was called, whereby I need to be able to check with what argument it was called. For this purpose I have the following unit test:
@Test
void TestDoSomehing(){
SubClass sb = mock(SubClass.class);
Example ex = new Example(sb);
ArgumentCaptor<Map<String, CompoundClass>> argCaptor = ArgumentCaptor.forClass(Map<String, CompoundClass>.class);
ex.doSomeThing();
verify(sb).doSomeThingSubClass(argCaptor.capture());
System.out(argCaptor.getValue().get('x').a);
}
The problem is that the above initialization of the argCaptor produces the following error message: "Cannot select from parametrized type". Therefore, the question is how to declare an initialize in a correct way the argument captor for a map object like Map<String, SomeCustomeClass>
? Thanks in advance!
Mockito ArgumentCaptor is used to capture arguments for mocked methods. ArgumentCaptor is used with Mockito verify() methods to get the arguments passed when any method is called. This way, we can provide additional JUnit assertions for our tests.
public class ArgumentCaptor<T> extends Object. Use it to capture argument values for further assertions. Mockito verifies argument values in natural java style: by using an equals() method. This is also the recommended way of matching arguments because it makes tests clean & simple.
You can use Mockito's Captor annotation to declare a parameterized instance of ArgumentCaptor. One of the advantages of using @Captor annotation is that you can avoid warnings related capturing complex generic types. Thanks for contributing an answer to Stack Overflow!
There are some important methods of the ArgumentCaptor class that are given below: It is used to capture the method arguments. It is used to build a new ArgumentCaptor. It is used to return all the captured values.
Open Eclipse. Go to File=>New=>Java Project. In the ‘Project name’ enter ‘MockitoCaptorExample’. Eclipse will create a ‘src’ folder.
org.mockito.exceptions.base.MockitoException: No argument value was captured! This exception message is confusing and can trip you to believing that you have issues in your test. However, the issue is in the code you are testing and not in your test.
You can do it either:
with @SuppressWarnings("unchecked")
@Test
@SuppressWarnings("unchecked")
void TestDoSomething(){
SubClass sb = mock(SubClass.class);
Example ex = new Example(sb);
ArgumentCaptor<Map<String, CompoundClass>> argCaptor = ArgumentCaptor.forClass(Map.class);
ex.doSomeThing();
verify(sb).doSomeThingSubClass(argCaptor.capture());
System.out.println(argCaptor.getValue().get("x").a);
}
or with junit5 and @Captor annotation:
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import java.util.HashMap;
import java.util.Map;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestInstance;
import org.junit.jupiter.api.TestInstance.Lifecycle;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Captor;
import org.mockito.junit.jupiter.MockitoExtension;
@ExtendWith(MockitoExtension.class)
@TestInstance(Lifecycle.PER_METHOD)
public class TestDoSomething {
@Captor
private ArgumentCaptor<Map<String, CompoundClass>> argCaptor;
@Test
void TestDoSomething2(){
SubClass sb = mock(SubClass.class);
Example ex = new Example(sb);
ex.doSomeThing();
verify(sb).doSomeThingSubClass(argCaptor.capture());
System.out.println(argCaptor.getValue().get("x").a);
}
}
You can use Mockito's Captor
annotation to declare a parameterized instance of ArgumentCaptor
.
For example, the following test compiles and outputs aa
:
@Captor
private ArgumentCaptor<Map<String, CompoundClass>> argCaptor;
@Test
void TestDoSomehing(){
MockitoAnnotations.initMocks(this);
SubClass sb = mock(SubClass.class);
Example ex = new Example(sb);
ex.doSomeThing();
verify(sb).doSomeThingSubClass(argCaptor.capture());
System.out.println(argCaptor.getValue().get("x").a);
}
From the Javadocs:
One of the advantages of using
@Captor
annotation is that you can avoid warnings related capturing complex generic types.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With