使用 Mockito 2 模拟服务导致存根错误

新手上路,请多包涵

我尝试使用 Mockito 模拟一个类的行为。这使用 Mockito 1.x 有效。迁移到 JUnit 5 和 Mockito 2 它似乎不再工作了。

 @ExtendWith(MockitoExtension.class)
public class MockitoExample {

  static abstract class TestClass {
    public abstract int booleanMethod(boolean arg);
  }

  @Mock
  TestClass testClass;

  @BeforeEach
  public void beforeEach() {
    when(testClass.booleanMethod(eq(true))).thenReturn(1);
    when(testClass.booleanMethod(eq(false))).thenReturn(2);
  }

  @Test
  public void test() {
    assertEquals(1,testClass.booleanMethod(true));
    assertEquals(2,testClass.booleanMethod(false));
  }
}

期望是,模拟的 TestClass 显示测试方法中测试的行为。

我得到的错误是:

 org.mockito.exceptions.misusing.PotentialStubbingProblem:

  Strict stubbing argument mismatch. Please check:
   - this invocation of 'booleanMethod' method:
      testClass.booleanMethod(false);
      -> at org.oneandone.ejbcdiunit.mockito_example.MockitoExample.beforeEach(MockitoExample.java:30)
   - has following stubbing(s) with different arguments:
      1. testClass.booleanMethod(false);
        -> at org.oneandone.ejbcdiunit.mockito_example.MockitoExample.beforeEach(MockitoExample.java:29)
  Typically, stubbing argument mismatch indicates user mistake when writing tests.
  Mockito fails early so that you can debug potential problem easily.
  However, there are legit scenarios when this exception generates false negative signal:
    - stubbing the same method multiple times using 'given().will()' or 'when().then()' API
      Please use 'will().given()' or 'doReturn().when()' API for stubbing.
    - stubbed method is intentionally invoked with different arguments by code under test
      Please use default or 'silent' JUnit Rule (equivalent of Strictness.LENIENT).
  For more information see javadoc for PotentialStubbingProblem class.

在这两种情况下,参数 false 似乎是匹配的,尽管我显然匹配 true

这是 Mockito 2.17 中的错误还是误解。我应该/如何使用 Mockito 2.x 来模拟具有不同布尔参数的调用?

示例 也可以在 github 上找到。但是 surefire 将只使用开始测试

mvn test -Dtest=MockitoExample

使用 Mockito 2.21 执行测试会导致相同的结果。

原文由 aschoerk 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 3.2k
2 个回答

从 Mockito 2.20 开始,也可以在本地添加 lenient()

 @ExtendWith(MockitoExtension.class)
public class MockitoExample {

  static abstract class TestClass {
    public abstract int booleanMethod(boolean arg);
  }

  @Mock
  TestClass testClass;

  @BeforeEach
  public void beforeEach() {
    lenient().when(testClass.booleanMethod(eq(true))).thenReturn(1);
    lenient().when(testClass.booleanMethod(eq(false))).thenReturn(2);
  }

  @Test
  public void test() {
    assertEquals(1,testClass.booleanMethod(true));
    assertEquals(2,testClass.booleanMethod(false));
  }
}

原文由 aschoerk 发布,翻译遵循 CC BY-SA 4.0 许可协议

使用严格的存根(Mockito 的默认行为)在同一方法上调用多个 when s 将重置该模拟。解决方案是调用 when 一次 并将逻辑放在 Answer 中:

 @BeforeEach
public void beforeEach() {
    when(testClass.booleanMethod(anyBoolean())).thenAnswer(invocationOnMock -> {
        if ((boolean) invocationOnMock.getArguments()[0]) {
            return 1;
        }
        return 2;
    });
}

或者,您可以使用宽松的模拟,但这并不总是一个好主意 - 宽松的模拟允许冗余存根,并使您更容易在测试中犯错误,这可能会导致“生产”代码中未被发现的错误:

 @ExtendWith(MockitoExtension.class)
@MockitoSettings(strictness = Strictness.LENIENT)
public class MockitoExample {

原文由 Mureinik 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题
logo
Stack Overflow 翻译
子站问答
访问
宣传栏