简体   繁体   中英

any(Classmember) returns null mockito

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM