【问题标题】:Mockito verify(...) fails - "Actually, there were zero interactions with this mock." in more than one test run sequentially [duplicate]Mockito verify(...) 失败 - “实际上,与此模拟的交互为零。”在多个测试中按顺序运行[重复]
【发布时间】:2016-03-05 16:13:58
【问题描述】:

我有一个 Wrapper 类,它不是 equals 方法,而是在包装对象上调用 equalsWithoutId 方法。在这里实现:

import org.apache.commons.lang3.Validate;

public class IdAgnosticWrapper {

    private final IdAgnostic wrapped;

    public IdAgnosticWrapper(IdAgnostic wrapped) {
        Validate.notNull(wrapped, "wrapped must not be null");
        this.wrapped = wrapped;
    }

    @Override
    public int hashCode() {
        return wrapped.hashCodeWithoutId();
    }

    @Override
    public boolean equals(Object obj) {
        if (!(obj instanceof IdAgnosticWrapper)) {
            return false;
        }
        return wrapped.equalsWithoutId(((IdAgnosticWrapper) obj).getWrapped());
    }

    public IdAgnostic getWrapped() {
        return wrapped;
    }
}

IdAgnostic 是一个简单的接口,可确保存在所需的方法

public interface IdAgnostic {
    int hashCodeWithoutId();
    boolean equalsWithoutId(Object o);
}

然后我有一些单元测试应该测试,如果 equals() 委托给 Wrapped#equalsWithoutId() 方法,hashCode() 委托给 Wrapped#hashCodeWithoutId。

现在我尝试通过这些测试来测试它

import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;

import static org.mockito.Mockito.verify;

public class IdAgnosticWrapperTest {

    @Mock
    private IdAgnostic wrappedMock;

    @InjectMocks
    private IdAgnosticWrapper tested;


    @BeforeMethod
    public void setUp() throws Exception {
        MockitoAnnotations.initMocks(this);
    }

    @Test
    public void testEquals_EqualsWithoutIdIsCalledOnWrapped() throws Exception {
        tested.equals(tested);
        verify(wrappedMock).equalsWithoutId(tested.getWrapped());
    }

    @Test
    public void testHashCode_HashCodeWithoutIdIsCalledOnWrapped() throws Exception {
        tested.hashCode();
        verify(wrappedMock).hashCodeWithoutId(); //line 34
    }
}

如您所见,我只是创建了包装的模拟并测试了 equals 和 hashcode 是否委托了功能。

如果我单独运行测试,一切正常,但如果我按顺序运行两个测试,第二个测试会失败并显示此消息

Wanted but not invoked:
wrappedMock.hashCodeWithoutId();
-> at com.my.app.utils.IdAgnosticWrapperTest.testHashCode_HashCodeWithoutIdIsCalledOnWrapped(IdAgnosticWrapperTest.java:34)
Actually, there were zero interactions with this mock.

为什么会这样?

【问题讨论】:

  • 您可以尝试在调试器中执行它。那样可能会更清楚。
  • 我做了,但没有发现任何有趣的东西。
  • 重点是,在“hashcode”方法中设置一个断点,看看它是否到达了那行代码。如果是,请检查“包装器”对象并确保它是模拟对象。我认为没有理由不这样做,但这些都是需要检查的重要事项。
  • 如果这没有给您任何线索,并且您在这里没有得到回复,请在模拟用户邮件列表上写下您的所有详细信息。
  • 如果你使用的是 apache commons,如果你升级你可以访问“Diffable”接口——这可能是你想要考虑实现的。根据您在此处所拥有的内容,您似乎想要根据数据库中键的 IDnot 制作某种“业务平等”逻辑,除非我在这里完全偏离了基础。

标签: java mockito testng


【解决方案1】:

实际上,这里发生的情况是@InjectMocks 无法正确注入构造函数参数wrapped。根据Javadoc for @InjectMocks,这是当前行为。因此,除非您想使用 setter 注入,否则您需要删除 @InjectMocks 注释。查看修改后的代码:

public class IdAgnosticWrapperTest {

  @Mock
  private IdAgnostic wrappedMock;

  private IdAgnosticWrapper tested;

  @BeforeMethod
  public void setUp() throws Exception {
    MockitoAnnotations.initMocks(this);

    this.tested = new IdAgnosticWrapper(this.wrappedMock);
  }

  @Test
  public void testEquals_EqualsWithoutIdIsCalledOnWrapped()
      throws Exception {
    tested.equals(tested);
    verify(wrappedMock).equalsWithoutId(tested.getWrapped());
  }

  @Test
  public void testHashCode_HashCodeWithoutIdIsCalledOnWrapped()
      throws Exception {
    tested.hashCode();
    verify(wrappedMock).hashCodeWithoutId(); //line 34
  }
}

当我运行上面的代码时,两个测试顺序一起运行并通过了。

【讨论】:

  • @InjectMocks not 在它注释的字段中模拟对象,而是允许 Mockito 反射性地将 @Mock@Spy 字段中的模拟安装/注入到构造函数和字段中@InjectMocked 对象。也就是说,@InjectMocks 是一个问题,因为 TestNG 重用了测试对象,而 Mockito 由于字段的 final 修饰符而无法字段注入 IdAgnosticWrapper。查看更多here
  • @JeffBowman 好电话。我完全错过了。我已经相应地更新了我的答案。谢谢你让我做作业。 :-)
  • 感谢您提供的解决方案,但问题不在于该包装字段是最终的。问题是, MockitoAnnotations.initMocks(this);创建了私有 IdAgnostic WrapperMock 的新实例;但没有创建私有 IdAgnosticWrapper 测试的新实例;因此,我验证了在对象上调用了该方法,该方法从未被包装器包装(存在上一个测试中的实例)。这个问题似乎与stackoverflow.com/questions/20046210/… 重复
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-11-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多