如何单元测试图节点与mockito



考虑以下类:

public class Node {
    private final Collection<Node> mDependants = new ArrayList<>();
    private Node mDependency;
    public void initialize(final Node node) {
        // complex code that might call registerDependency;
    }
    private void registerDependency(final Node node) {
        mDependency = node;
        node.registerDependent(this);
    }
    private void registerDependent(final Node node) {
        mDependants.add(node);
    }
}

然后是单元测试,如:

import static org.mockito.Mockito.mock;
public class NodeTest {
    private Node mTarget;
    private Node mDependent;
    @Before
    public void setUp() {
        mTarget = new Node();
        mDependent = mock(Node.class);
    }
    @Test
    public void test() {
        mTarget.initialize(mDependent);
    }
}

由于registerDependent是私有的,mockito实际上不会模拟它。由于mTarget实际上是一个真实的实例,因此当通过initialize执行registerDependency方法时,它将尝试在mock上执行私有方法registerDependent。作为mock的mock将不会被初始化,并且mDependants实际上将为空,导致mdependents .add(node)上的NullPointerException。

正确的测试方法应该是什么?我应该使用两个真实节点而不是一个模拟节点吗?我是否应该使方法公开以允许对方法进行嘲弄?我还错过了别的选择吗?

因为这是一个针对Node的测试,所以尽可能避免模拟Node。比起测试实现是否正确,测试mock框架是否正确工作或规范是否正确定义要容易得多。

我很喜欢JB Nizet在这里给出的SO答案:如果你正在建造一个炸弹雷管,你的频繁测试应该使用真实的雷管和模拟的炸弹。模拟应该针对被测系统的依赖项协作者,而不是被测系统本身。

如果您的Node是一个接口,并且您的NodeImpl实现可以接受任何节点作为依赖,那么使用mock Node可能更有意义,因为您可以传入具有不同实现的节点,这些实现甚至可能还不存在,而且当您将自己限制为mock接口时,许多Mockito的问题都会消失。然而,由于Node和它的依赖Node是相同的具体类,并且依赖于私有实现细节,因此您可能会更成功地处理实际实例。

此外,这些节点不太可能涉及繁重的服务层或其他依赖关系,这些依赖关系使它们易于嘲弄,并且节点是否表现良好是毫无疑问的:您可以在相邻的测试中看到它。

(旁白:有一些技术可以模拟被测系统中的单个方法——"部分模拟"——但当您不使用遗留代码或繁重的服务时,最好避免使用这些技术。)

相关内容

  • 没有找到相关文章

最新更新