嵌套方法在Mockito中嘲弄

use*_*283 5 java junit mocking mockito

我有以下Java类:

public class A
{
    @Autowired
    private B b;
    public int aFn()
    {
        int something = b.bFn();
    }
}
public class B
{
    @Autowired
    private C c;
    public int bFn()
    {
        int something = c.cFn();
    }
}
public class C
{
    public int cFn()
    {
        return 231;
    }
}
Run Code Online (Sandbox Code Playgroud)

以下测试使用Mockito测试上面的代码:

public class test
{
    @Autowired
    private A a;

    private C c;

    @Test
    public void testA()
    {
        c = mock(C.class);
        when(c.cFn(),anyInt()).thenReturn(something);
        assertEquals(0, a.aFn());
    }
}
Run Code Online (Sandbox Code Playgroud)

当我调试testA时,我发现真正的c.Cfn()被执行,而不是被模拟的.我在这里做错了什么吗?请帮忙!

JB *_*zet 8

首先,您应该始终模拟对象的直接依赖关系,而不是它的传递依赖关系.所以你应该模拟B而不是C来测试A.然后你会通过模拟C来编写B的单元测试.

第二:你不是在单元测试中的任何地方注入模拟.你应该拥有的是:

public class Test {

    // not autowired here
    private A a;

    private B mockB;

    @Test
    public void testA() {
        mockB = mock(B.class);
        when(b.bFn(), anyInt()).thenReturn(something);

        // the missing part: injecting the mock into the tested object
        a = new A(mockB);
        // or a = new A();
        //    a.setB(mockB);

        assertEquals(0, a.aFn());
    }
}
Run Code Online (Sandbox Code Playgroud)

当你使用mock(B.class)时,你得到一个B的模拟实例.这并不意味着B的所有其他实例都会做模拟所做的事情.

模拟C来测试A是一种不好的做法:单元测试应该测试一个类而不是其他类.但是如果你真的想要它,那么创建一个模拟C,创建一个B并在其中注入模拟C,然后创建一个A并在其中注入B.

A --> B --> mockC
Run Code Online (Sandbox Code Playgroud)

  • JB,您只讨论了单元测试,但问题从未指定测试是单元测试,或者 SUT 是单个类。在许多情况下,有一个 SUT 包含多个类的测试是有意义的 - 在这种情况下是 A 类和 B 类。我经常自己编写这样的测试,特别是如果 B 类包含许多有助于履行合同的逻辑A 类。我不同意您将其描述为“不良做法”,只要明确哪些类包含在哪些测试中即可。你回答的最后一段救了你,赢得了我的赞成票! (2认同)