Mockito 为通用 @BeforeEach 设置方法中定义的存根抛出 UnnecessaryStubbingException

Mockito throws UnnecessaryStubbingException for stub defined in generic @BeforeEach setup method

我有一个单元测试 class,我的被测单元依赖于另一个 class。使用 Mockito 模拟依赖关系,然后使用 JUnit 的 @BeforeEach 注释在每个单元测试之前使用 运行 的通用存根进行设置。请参阅下面的伪代码。

@ExtendWith(MockitoExtension.class)
public class FooFactoryTest {

    @Mock
    private BarDependency barDependency;

    @InjectMocks
    private FooFactory unitUnderTest;

    @BeforeEach
    public void setup() {
        when(barDependency.leftBar(any())).thenReturn(new Bar());
        when(barDependency.rightBar(any())).thenReturn(new Bar());
    }

   ... many tests ...

此设置非常适合我的 10 个单元测试中的 9 个。不幸的是,我的一项测试因以下错误而失败:

org.mockito.exceptions.misusing.UnnecessaryStubbingException: 
Unnecessary stubbings detected.
Clean & maintainable test code requires zero unnecessary code.
Following stubbings are unnecessary (click to navigate to relevant line of code):
  1. -> at nl.devillers.mockito.FooFactoryTest.setup(FooFactoryTest.java:69)
Please remove unnecessary stubbings or use 'lenient' strictness. More info: javadoc for UnnecessaryStubbingException class.

现在,我明白了这个错误以及它被抛出的原因,因为在那个特定的测试中,我的被测单元很早就短路了,并且没有击中所有已设置的存根。我知道 Mockito 中有一个 lenient 选项,但这会禁用 entire class/project.

的检查

我的问题是:如何为一个特定的 单元测试禁用此严格性

再说一次:我 想在 class 或项目级别禁用严格性,因为我认为这是有价值的检查。我也 想将我的设置代码移动到确实需要存根的测试中,因为那样我必须将设置代码复制九次。在这种情况下,我只想禁用或跳过此特定测试的检查。

您可以通过使用未调用的存根重置模拟来避免在测试级别进行此检查。这有点变通,但它可以让您通过测试,而不必为整个测试设置模拟 class 或从您的设置方法中完全删除模拟。

要重置您的 barDependency 模拟,请将以下代码行添加到 失败的测试的末尾 UnnecessaryStubbingException

Mockito.reset(barDependency);

如果none barDependency 上的存根正在被使用,您也可以将此行放在测试的开头以及其他安排, 这有点干净。或者,将它放在测试方法的顶部,然后设置您 do 需要的存根。这实质上会覆盖您的通用设置方法中正在设置的任何内容。

您还可以在 @BeforeEach 的代码中使用 lenient,如下所示:

@BeforeEach
public void setup() {
    lenient().when(barDependency.leftBar(any())).thenReturn(new Bar());
    lenient().when(barDependency.rightBar(any())).thenReturn(new Bar());
}

根据 UnnecessaryStubbingException 中的文档,这应该不是必需的:

Mockito JUnit Runner triggers UnnecessaryStubbingException only when none of the test methods use the stubbings. This means that it is ok to put default stubbing in a 'setup' method or in test class constructor. That default stubbing needs to be used at least once by one of the test methods.