I am trying to do when().thenReturn() but facing issues. Following is the sample code that I came up with for SOers:
import java.util.List;
public class Sample {
public void function(List<SampleA> list) {
for (SampleA s : list) {
List<SampleB> nameList = s.v1;
for (SampleB m : nameList) {
SampleC value = m.getV2();
if (value != null) {
doSomething(value);
} else {
LOGGER.warn("No valid value");
}
}
}
}
}
public class SampleA{
List<SampleB> v1;
}
public class SampleB{
SampleC v2;
public SampleC getV2(){
return this.v2;
}
}
This might be silly but I just want to understand why can't I do:
SampleB sampleB = new SampleB();
when(sampleB.getV2()).thenReturn(any(SampleC.class));
any(…)
is an ArgumentMatcher
. It is used to match arguments. You cannot use it to return instances of classes. What would "any SampleC" be?
You'd use it with mock objects, like so:
SampleInterface sample = Mockito.mock(SampleInterface.class);
when(sample.function(any(List.class))).thenReturn(new ArrayList<>());
// or: .thenAnswer(a -> new ArrayList<>()); to return a new instance for each call
you can't use ArgumentMatchers inside thenReturn or thenAnswer. You have to specify exactly what to return. For Example:
SampleB sampleB = mock(SampleB.class)
when(sampleB.getV2()).thenReturn(new SampleC());
I'm guessing that you are trying to test Sample.function
and are trying to work out how to mock SampleC
values. If so, then your code should probably look something like:
@Test
void testFunction() {
SampleC mockC = mock(SampleC.class);
SampleB mockB = mock(SampleB.class);
SampleA mockA = mock(SampleA.class);
when(mockB.getV2()).thenReturn(mockC);
when(mockA.getV1()).thenReturn(List.of(mockB));
Sample sample = new Sample();
sample.function(List.of(mockA));
// verify doSomething was called with mockC as its argument
when(mockB.getV2()).thenReturn(null);
sample.function(List.of(mockA));
// verify "No valid value" was logged
}
I've added a getV1
method rather than direct access to the field because my fingers refuse to write the code that directly accesses a public field:-)
If you're struggling with verifying that doSomething
was called then that's where argument matching comes in. Ideally you'd have a SomethingDoer
that you inject into your sample:
interface SomethingDoer {
void doSomething(SampleC sample);
}
class Sample {
private final SomethingDoer somethingDoer;
public Sample(SomethingDoer somethingDoer) {
this.somethingDoer = somethingDoer;
}
}
Then you'd add the following to your test:
SomethingDoer doer = mock(SomethingDoer.class);
Sample sample = new Sample(doer);
...
verify(doer).doSomething(mockC);
Also note that the code above is poor style: the tests should be split up with the setup code in a @BeforeEach
method. I've just put it in a single test to keep the answer simple.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.