简体   繁体   English

any(Classmember) 返回 null mockito

[英]any(Classmember) returns null mockito

I am trying to do when().thenReturn() but facing issues.我正在尝试做 when().thenReturn() 但面临问题。 Following is the sample code that I came up with for SOers:以下是我为 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 . any(…)是一个ArgumentMatcher It is used to match arguments.用于匹配 arguments。 You cannot use it to return instances of classes.您不能使用它来返回类的实例。 What would "any SampleC" be? “任何 SampleC”是什么?

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.您不能在 thenReturn 或 thenAnswer 中使用 ArgumentMatchers。 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.我猜您正在尝试测试Sample.function并试图弄清楚如何模拟SampleC值。 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:-)我添加了一个getV1方法而不是直接访问该字段,因为我的手指拒绝编写直接访问公共字段的代码:-)

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:如果您正在努力验证是否调用了doSomething ,那么这就是参数匹配出现的地方。理想情况下,您应该将SomethingDoer注入到您的样本中:

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.另请注意,上面的代码风格很差:测试应该与@BeforeEach方法中的设置代码分开。 I've just put it in a single test to keep the answer simple.我只是把它放在一个测试中以保持答案简单。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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