简体   繁体   English

Mockito 没有从具有多个“何时”条件的模拟方法返回正确结果

[英]Mockito not returning correct result from mocked method with multiple “when” conditions

I have a simple DTO class:我有一个简单的 DTO class:

@Data // lombok
public class MyObj {
    private int id;
    private String someProperty;
}

and a class with some computation logic for the DTO object:和一个 class 以及 DTO object 的一些计算逻辑:

public class MyClass {
    public String doSomething(MyObj obj) {
        // some calculations
    }
}

I tried to mock MyClass to use it in some unit tests, but encountered a weird problem.我试图模拟MyClass以在一些单元测试中使用它,但遇到了一个奇怪的问题。 Therefore, I created this minimal test code to illustrate the issue:因此,我创建了这个最小的测试代码来说明这个问题:

@RunWith(MockitoJUnitRunner.class)
public class MyClassTest {
    private final MyObj myObjFirst = new MyObj();
    private final MyObj myObjSecond = new MyObj();

    @Mock
    private MyClass myClass;

    @Before
    public void setUp() {
        doReturn("OTHER")
                .when(myClass)
                .doSomething(any(MyObj.class));
        doReturn("FIRST")
                .when(myClass)
                .doSomething(myObjFirst);
        doReturn("SECOND")
                .when(myClass)
                .doSomething(myObjSecond);
    }

    @Test
    public void doSomething() {
        assertEquals("FIRST", myClass.doSomething(myObjFirst)); // fail, actual value "SECOND"
        assertEquals("SECOND", myClass.doSomething(myObjSecond));
        assertEquals("OTHER", myClass.doSomething(new MyObj()));
        assertEquals("OTHER", myClass.doSomething(new MyObj()));
    }
}

For some reason, myClass.doSomething(myObjFirst) produces the string "SECOND" instead of the expected "FIRST" , therefore the test fails at the first assert.出于某种原因, myClass.doSomething(myObjFirst)产生字符串"SECOND"而不是预期的"FIRST" ,因此测试在第一次断言时失败。

What am I doing wrong?我究竟做错了什么?

Solution解决方案

When stubbing, wrap the expected objects into Mockito.same to match them by reference ( see this answer for different matchers):存根时,将预期对象包装到Mockito.same以通过引用匹配它们(请参阅此答案以了解不同的匹配器):

@Before
public void setUp() {
    doReturn("OTHER")
            .when(myClass)
            .doSomething(any(MyObj.class));
    doReturn("FIRST")
            .when(myClass)
            .doSomething(same(myObjFirst)); // <-- HERE
    doReturn("SECOND")
            .when(myClass)
            .doSomething(same(myObjSecond)); // <-- AND HERE
}

Explanation解释

Mockito seems to use the equals method to detect the given argument to the mocked method (reference to docs needed). Mockito 似乎使用equals方法来检测模拟方法的给定参数(需要参考文档)。

Due to Lombok's @Data annotation , a MyObj.equals implementation is generated, which compares the objects by their fields id and someProperty .由于Lombok 的@Data注释,生成了一个MyObj.equals实现,它通过字段idsomeProperty比较对象。 Because both fields are null on myObjFirst and myObjSecond , and because last stubbing has the highest importance , Lombok first compares the argument given to myClass.doSomething against myObjSecond , immediately finding a match and returning "SECOND" .因为myObjFirstmyObjSecond上的两个字段都是null ,并且因为最后一个存根具有最高的重要性,所以 Lombok 首先将提供给myClass.doSomething的参数与myObjSecond进行比较,立即找到匹配项并返回"SECOND"

If Lombok's @Data annotation was omitted from MyObj , the above code would work as-is, because then MyObj.equals method would default to object reference comparison, making myObjFirst not equal to myObjSecond .如果MyObj中省略了 Lombok 的@Data注释,则上述代码将按原样工作,因为MyObj.equals方法将默认为 object 参考比较,从而使myObjFirst不等于myObjSecond

In this case, however, myObjFirst equals myObjSecond equals new MyObj() , unless their properties are set to different values.但是,在这种情况下, myObjFirst等于myObjSecond等于new MyObj() ,除非它们的属性设置为不同的值。

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

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