2

我正在使用 Mockito 对业务对象进行单元测试。业务对象使用通常从数据库获取数据的 DAO。为了测试业务对象,我意识到使用单独的内存 DAO(将数据保存在 HashMap 中)比编写所有

when(...).thenReturn(...)

陈述。为了创建这样的 DAO,我首先部分模拟了我的 DAO 接口,如下所示:

when(daoMock.getById(anyInt())).then(new Answer() {
    @Override
    public Object answer(InvocationOnMock invocation) throws Throwable {
        int id = (Integer) invocation.getArguments()[0];
        return map.get(id);
    }
});

但我突然想到,自己实现一个全新的 DAO 实现(使用内存中的 HashMap)甚至不使用 Mockito(无需从 InvocationOnMock 对象中获取参数)并让测试的业务对象使用这个新的更容易道。

此外,我读过部分模拟被认为是不好的做法。我的问题是:就我的情况而言,我正在做的事情是不好的做法吗?有什么缺点?对我来说这似乎没问题,我想知道潜在的问题可能是什么。

4

2 回答 2

2

我想知道为什么你需要你的假 DAO 由HashMap. 我想知道您的测试是否太复杂。我非常喜欢使用非常简单的测试方法,每种方法都可以测试 SUT 行为的一个方面。原则上,这是“每个测试一个断言”,尽管有时我会得到少量的实际assertverify行,例如,如果我断言一个复杂对象的正确性。请阅读http://blog.atrumfutura.com/2009/02/unit-testing-one-test-one-assertion-why-it-works/http://blog.jayfields.com/2007/06/testing -one-assertion-per-test.html以了解有关此原理的更多信息。

所以对于每种测试方法,你不应该一遍又一遍地使用你的假 DAO。可能只有一次,最多两次。因此,在HashMap我看来,拥有大量数据似乎是多余的,或者表明您的测试做得比它应该做的要多。对于每种测试方法,您实际上应该只需要一两项数据。如果您使用 DAO 接口的 Mockito 模拟设置这些,并将您when ... thenReturn的测试方法本身放入,每个测试都将简单易读,因为特定测试使用的数据将立即可见。

您可能还想阅读“安排、行动、断言”模式(http://www.arrangeactassert.com/why-and-what-is-arrange-act-assert/和 http://www.arrangeactassert.com/why-and-what-is-arrange-act-assert/和http://www. telerik.com/help/justmock/basic-usage-arrange-act-assert.html)并注意在每个测试方法中实现此模式,而不是将其不同部分分散在您的测试类中。

如果没有看到更多的实际测试代码,很难知道给你什么其他建议。Mockito 应该让嘲笑更容易,而不是更难;所以如果你有一个测试没有发生在你身上,那么肯定值得问问你是否在做一些非标准的事情。您所做的不是“部分嘲弄”,但对我来说,这确实像是一种测试气味。尤其是因为它将您的许多测试方法结合在一起 - 问问自己,如果您必须更改HashMap.

您可能会发现https://softwareengineering.stackexchange.com/questions/158397/do-large-test-methods-indicate-a-code-smell也很有用。

于 2012-10-03T19:07:11.157 回答
1

在测试我的课程时,我经常使用 Mockito 制作的模拟和假货的组合,这正是你所描述的。在您的情况下,我同意虚假的实现听起来更好。

部分模拟并没有什么特别的问题,但是它使确定何时调用真实对象以及何时调用模拟方法变得更加困难——尤其是因为 Mockito 默默地无法模拟最终方法。对原始类的看似无辜的更改可能会更改部分模拟的实现,从而导致您的测试停止工作。

如果你有灵活性,我建议提取一个暴露你需要调用的方法的接口,这样无论你选择mock还是fake都会更容易。

要编写一个假的,使用一个简单的类(如果你愿意,可以嵌套在你的测试中)实现那个没有 Mockito 的小接口。这将很容易看到正在发生的事情;缺点是如果你写了一个非常复杂的 Fake,你可能会发现你也需要测试 Fake。如果你有很多测试可以使用一个好的 Fake 实现,那么这可能值得额外的代码。

我强烈推荐Martin Fowler 的一篇文章“Mocks are not Stubs” (以他的书Refactoring闻名)。他回顾了不同类型的测试替身的名称,以及它们之间的区别。

于 2012-10-03T16:52:38.873 回答