Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/365.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 使用Mockito 2模拟服务导致存根错误_Java_Unit Testing_Mocking_Mockito_Junit5 - Fatal编程技术网

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

Java 使用Mockito 2模拟服务导致存根错误,java,unit-testing,mocking,mockito,junit5,Java,Unit Testing,Mocking,Mockito,Junit5,我尝试使用Mockito模拟类的行为。 这在使用Mockito1.x时有效。迁移到JUnit5和Mockito2后,它似乎不再工作了 @ExtendWith(MockitoExtension.class) public class MockitoExample { static abstract class TestClass { public abstract int booleanMethod(boolean arg); } @Mock TestClass tes

我尝试使用Mockito模拟类的行为。 这在使用Mockito1.x时有效。迁移到JUnit5和Mockito2后,它似乎不再工作了

@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执行测试会得到相同的结果

使用严格存根(Mockito的默认行为),在同一方法上调用多个
时,将重置该mock。解决方案是在
时调用一次
,并在
应答中包含逻辑:

@BeforeEach
public void beforeEach() {
    when(testClass.booleanMethod(anyBoolean())).thenAnswer(invocationOnMock -> {
        if ((boolean) invocationOnMock.getArguments()[0]) {
            return 1;
        }
        return 2;
    });
}
或者,您可以使用宽松的模拟,但这并不总是一个好主意-宽松的模拟允许冗余存根,并使您更容易在测试中出错,这可能会导致“生产”代码中出现未被注意到的错误:


由于第一个答案出人意料,我检查了以下内容:

interface Poops {
    String get(boolean is);
}

@Test
void test1() {
    Poops a = mock(Poops.class);

    when(a.get(eq(true))).thenReturn("1");
    when(a.get(eq(false))).thenReturn("2");

    Assertions.assertEquals("1", a.get(true));
    Assertions.assertEquals("2", a.get(false));
}
它与Mockito 2.21.0配合使用

更新
问题似乎在于Jupiter Mockito扩展,它将默认设置更改为
STRICT.STRICT_STUBS

由于Mockito 2.20,也可以在本地添加lenient()


Mockito 1和2没有相同的“严格”级别。
此外,在JUnit4或JUnit5中使用Mockito2,默认级别仍然会有所不同

总而言之:

三级严格:

  • 宽松
    :最低限度的严格
  • 警告
    :向控制台发出额外警告
  • STRICT_STUBS
    :通过在潜在误用时引发异常来确保干净的测试,但也可能产生一些误报
根据使用的API的默认有效级别:

  • 莫基托1:
    宽大
  • 带有JUnit4的Mockito 2:
    WARN
  • 带有JUnit5的Mockito2(
    MockitoExtension.class
    ):
    STRICT\u STUBS
  • Mockito 3:计划严格执行\u STUBS
更多详细信息

实际的Mockito文档非常清楚:

各国:

在模拟会话期间配置Mockito的“严格性”。a 会话通常映射到单个测试方法调用。严格 推动更清洁的测试和更高的生产效率。最简单的方法 利用Mockito的JUnit支持增强严格性 (MockitoRule或MockitoJUnitRunner)。如果无法使用JUnit支持 MockitoSession是一条路要走

严格程度如何影响测试行为(模拟 会议)

1.
严格。宽松
-没有添加行为。仅当您不能使用严格的存根或警告时,才建议使用默认的Mockito 1.x

2.
严格性。警告
-有助于保持测试干净并提高可调试性。报告有关未使用存根和存根的控制台警告 参数不匹配(请参见org.mockito.quality.MockitoHint) 使用JUnitRule或MockitoJUnitRunner时Mockito 2.x的行为。 如果不能使用严格的_存根,建议使用

3.
严格。严格的存根
-确保干净的测试,减少测试代码重复,提高可调试性。灵活性的最佳组合 以及生产力。强烈推荐。计划作为Mockito的默认设置 v3.有关详细信息,请参见STRICT_存根

但是不管抛出的异常与消息相关联

“具有以下具有不同参数的存根”

似乎是一个过于严格的检查。 异常消息以某种方式证明:

但是,当此异常生成false时,存在合法的场景 负信号:

  • 被测代码故意用不同的参数调用stubbed方法
因此,默认情况下禁止它似乎太过分了。
因此,如果您使用JUnit5,作为
严格存根
的替代方法,您可以使用
警告
,但通常要避免
过于安静的宽松

除了
MockitoExtension
,mockitojunitjupiter
库还提供
@MockitoSettings
可以在方法级别和类级别使用

以下是一个例子:

import java.util.List;

import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mockito;
import org.mockito.junit.jupiter.MockitoExtension;
import org.mockito.junit.jupiter.MockitoSettings;
import org.mockito.quality.Strictness;

@ExtendWith(MockitoExtension.class)
public class FooTest {

    @MockitoSettings(strictness = Strictness.WARN)
    @Test
    void foo() throws Exception {
        List<String> strings = Mockito.mock(List.class);
        Mockito.when(strings.add("a"))
               .thenReturn(true);
        Mockito.when(strings.add("b"))
               .thenReturn(false);
    }

    @Test
    void fooKo() throws Exception {
        List<String> strings = Mockito.mock(List.class);
        Mockito.when(strings.add("a"))
               .thenReturn(true);
        Mockito.when(strings.add("b"))
               .thenReturn(false);

    }

}
作为另一种选择,您也可以使用 aschoerk对特定调用应用宽松严格。 您还可以在模拟实例化时将每个模拟调用设置为宽松:

@Test
void foo() throws Exception {
    List<String> strings = Mockito.mock(List.class, Mockito.withSettings()
                                                           .lenient());
     ....
}
@测试
void foo()引发异常{
List strings=Mockito.mock(List.class,Mockito.withSettings()
.宽大(;
....
}

真的吗?我必须使用答案,解释那些最初实现了非常好的DSL的论点,并使存根更容易出错?在这种情况下,最好不要使用mockito并注入真实的模拟(至少,如果您使用的是spring或weld),对不起,非常感谢您的回答。这似乎是一种前进的方式。org.mockito.quality.Strictness.lenient如果您可以使用
doReturn()。当()
语法时,移植到该语法是一种不错的方法。如果您有新问题,请单击按钮提问。如果此问题有助于提供上下文,请包含指向此问题的链接。-@Draken将其作为注释会更好,但注释不允许代码片段。不,我没有其他问题,因为一切都按照我的预期进行
import java.util.List;

import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mockito;
import org.mockito.junit.jupiter.MockitoExtension;
import org.mockito.junit.jupiter.MockitoSettings;
import org.mockito.quality.Strictness;

@ExtendWith(MockitoExtension.class)
public class FooTest {

    @MockitoSettings(strictness = Strictness.WARN)
    @Test
    void foo() throws Exception {
        List<String> strings = Mockito.mock(List.class);
        Mockito.when(strings.add("a"))
               .thenReturn(true);
        Mockito.when(strings.add("b"))
               .thenReturn(false);
    }

    @Test
    void fooKo() throws Exception {
        List<String> strings = Mockito.mock(List.class);
        Mockito.when(strings.add("a"))
               .thenReturn(true);
        Mockito.when(strings.add("b"))
               .thenReturn(false);

    }

}
[MockitoHint] FooTest (see javadoc for MockitoHint): [MockitoHint] 1. Unused -> at FooTest.foo(FooTest.java:19) [MockitoHint] 2. Unused -> at FooTest.foo(FooTest.java:21)
@Test
void foo() throws Exception {
    List<String> strings = Mockito.mock(List.class, Mockito.withSettings()
                                                           .lenient());
     ....
}