12

这是我最初尝试使用 JMockIt 时发现的。我必须承认,我发现 JMockIt 文档对于它提供的内容非常简洁,因此我可能遗漏了一些东西。尽管如此,这是我的理解:

Mockito: List a = mock(ArrayList.class) does not stub out all methods
of List.class by default. a.add("foo") is going to do the usual thing
of adding the element to the list.

JMockIt: @Mocked ArrayList<String> a;
It stubs out all the methods of a by default. So, now a.add("foo")
is not going to work.

This seems like a very big limitation to me in JMockIt.
How do I express the fact that I only want you to give me statistics
of add() method and not replace the function implementation itself
What if I just want JMockIt to count the number of times method  add()
was called, but leave the implementation of add() as is?

I a unable to express this in JMockIt. However, it seems I can do this
in Mockito using spy()

我真的很想在这里被证明是错误的。JMockit 声称它可以做其他模拟框架所做的一切以及更多。好像不是这里的情况

@Test
public void shouldPersistRecalculatedArticle()
{
  Article articleOne = new Article();
  Article articleTwo = new Article();

  when(mockCalculator.countNumberOfRelatedArticles(articleOne)).thenReturn(1);
  when(mockCalculator.countNumberOfRelatedArticles(articleTwo)).thenReturn(12);
  when(mockDatabase.getArticlesFor("Guardian")).thenReturn(asList(articleOne, articleTwo));

  articleManager.updateRelatedArticlesCounters("Guardian");

  InOrder inOrder = inOrder(mockDatabase, mockCalculator);
  inOrder.verify(mockCalculator).countNumberOfRelatedArticles(isA(Article.class));
  inOrder.verify(mockDatabase, times(2)).save((Article) notNull());
}



@Test
public void shouldPersistRecalculatedArticle()
{
  final Article articleOne = new Article();
  final Article articleTwo = new Article();

  new Expectations() {{
     mockCalculator.countNumberOfRelatedArticles(articleOne); result = 1;
     mockCalculator.countNumberOfRelatedArticles(articleTwo); result = 12;
     mockDatabase.getArticlesFor("Guardian"); result = asList(articleOne, articleTwo);
  }};

  articleManager.updateRelatedArticlesCounters("Guardian");

  new VerificationsInOrder(2) {{
     mockCalculator.countNumberOfRelatedArticles(withInstanceOf(Article.class));
     mockDatabase.save((Article) withNotNull());
  }};
}

像这样的声明

inOrder.verify(mockDatabase, times(2)).save((Article) notNull());

在 Mockito 中,在 JMockIt 中没有等效项,正如您从上面的示例中看到的那样

new NonStrictExpectations(Foo.class, Bar.class, zooObj)
{
    {
        // don't call zooObj.method1() here
        // Otherwise it will get stubbed out
    }
};


new Verifications()
{
    {
        zooObj.method1(); times = N;
    }
};
4

2 回答 2

11

事实上,默认情况下,所有模拟 API 都会模拟或存根模拟类型中的每个方法。我认为您将mock(type)(“完全”模拟)与spy(obj)部分模拟)混淆了。

JMockit 可以做到这一切,在每种情况下都使用简单的 API。在JMockit 教程中,所有这些都通过示例进行了描述。为了证明,您可以查看示例测试套件(还有更多已从工具包的新版本中删除,但仍可以在旧的 zip 文件中找到),或许多 JMockit 集成测试(目前超过一千个) .

与 Mockito 等效的spy是 JMockit 中的“动态部分模拟”。只需将要部分模拟的实例作为参数传递给Expectations构造函数。如果没有记录期望,则在执行被测代码时执行真实代码。顺便说一句,Mockito 在这里有一个严重的问题(JMockit 没有),因为它总是执行真正的代码,即使它在内部被调用when(...)or verify(...); 正因为如此,人们不得不使用doReturn(...).when(...)来避免对间谍物体的意外发现。

关于调用的验证,JMockit Verifications API 比任何其他 API 都强大得多。例如:

new VerificationsInOrder() {{
    // preceding invocations, if any
    mockDatabase.save((Article) withNotNull()); times = 2;
    // later invocations, if any
}};
于 2011-10-26T18:02:37.470 回答
6

Mockito 是一个比 JMockIT 更古老的库,因此您可以预期它会有更多的特性。如果您想查看一些记录较少的功能,请阅读发布列表。JMockIT 作者制作了一个特性矩阵,其中他们错过了其他框架所做但他们没有做的每一件事,并且犯了几个错误(例如,Mockito 可以进行严格的模拟和排序)。

还编写了 Mockito 以启用单元级 BDD。这通常意味着,如果您的测试提供了如何使用代码的一个很好的示例,并且如果您的代码可爱、解耦且设计良好,那么您将不需要JMockIT 提供的所有恶作剧。开源中最难做的事情之一就是对许多从长远来看没有帮助的请求说“不”。

比较MockitoJMockIT 头版上的示例,看看真正的区别。这与您测试的内容无关,而与您的测试记录和描述班级行为的程度有关。

利益声明: Szczepan 和我在写 Mockito 的初稿时在同一个项目上,因为看到我们中的一些人推出了自己的存根类而不是使用当时现有的模拟框架。所以我觉得他都是为我写的,而且完全有偏见。谢谢斯泽潘。

于 2011-10-10T18:59:20.007 回答