Quick Guide to BDDMockito – BDDMockito的快速指南

最后修改: 2017年 12月 27日

中文/混合/英文(键盘快捷键:t)

1. Overview

1.概述

The BDD term was coined first by Dan North – back in 2006.

BDD一词是由Dan North – 早在2006年创造的。

BDD encourages writing tests in a natural, human-readable language that focuses on the behavior of the application.

BDD鼓励用自然的、人类可读的语言编写测试,重点是应用程序的行为。

It defines a clearly structured way of writing tests following three sections (Arrange, Act, Assert):

它定义了一种结构清晰的编写测试的方式,包括三个部分(安排、行动、断言)。

  • given some preconditions (Arrange)
  • when an action occurs (Act)
  • then verify the output (Assert)

The Mockito library is shipped with a BDDMockito class which introduces BDD-friendly APIs. This API allows us to take a more BDD friendly approach arranging our tests using given() and making assertions using then().

Mockito库中有一个BDDMockito类,它介绍了对BDD友好的API。该API允许我们采取对BDD更友好的方法,使用given()安排我们的测试,并使用then()做出断言。

In this article, we’re going to explain how to setup our BDD-based Mockito tests. We’ll also talk about differences between Mockito and BDDMockito APIs, to eventually focus on the BDDMockito API.

在这篇文章中,我们将解释如何设置我们基于BDD的Mockito测试。我们还将谈论MockitoBDDMockito API之间的差异,最终聚焦于BDDMockito API。

2. Setup

2.设置

2.1. Maven Dependencies

2.1.Maven的依赖性

The BDD flavor of Mockito is part of the mockito-core library, in order to get started we just need to include the artifact:

Mockito的BDD风味是mockito-core库的一部分,为了开始使用,我们只需要包含该工件。

<dependency>
    <groupId>org.mockito</groupId>
    <artifactId>mockito-core</artifactId>
    <version>2.21.0</version>
</dependency>

For the latest version of Mockito please check Maven Central.

关于Mockito的最新版本,请查看Maven Central

2.2. Imports

2.2.进口

Our tests can become more readable if we include the following static import:

如果我们包括以下静态导入,我们的测试可以变得更加可读。

import static org.mockito.BDDMockito.*;

Notice that BDDMockito extends Mockito, so we won’t miss any feature provided by the traditional Mockito API.

请注意,BDDMockito扩展了Mockito,所以我们不会错过传统Mockito API提供的任何功能。

3. Mockito vs. BDDMockito

3.Mockito与BDDMockito的对比

The traditional mocking in Mockito is performed using when(obj).then*() in the Arrange step.

Mockito中的传统嘲讽是在排列步骤中使用when(obj).then*()进行的。

Later, interaction with our mock can be validated using verify() in the Assert step.

之后,可以使用Assert步骤中的verify()来验证与我们的mock的交互。

BDDMockito provides BDD aliases for various Mockito methods, so we can write our Arrange step using given (instead of when), likewise, we could write our Assert step using then (instead of verify).

BDDMockito为各种Mockito方法提供了BDD别名,因此我们可以使用given(而不是when)来编写我们的Arrange步骤,同样,我们可以使用then(而不是verify)编写我们的Assert步骤。

Let’s look at an example of a test body using traditional Mockito:

让我们来看看一个使用传统Mockito的测试体的例子。

when(phoneBookRepository.contains(momContactName))
  .thenReturn(false);
 
phoneBookService.register(momContactName, momPhoneNumber);
 
verify(phoneBookRepository)
  .insert(momContactName, momPhoneNumber);

Let’s see how that compares to BDDMockito:

让我们看看与BDDMockito相比如何。

given(phoneBookRepository.contains(momContactName))
  .willReturn(false);
 
phoneBookService.register(momContactName, momPhoneNumber);
 
then(phoneBookRepository)
  .should()
  .insert(momContactName, momPhoneNumber);

4. Mocking With BDDMockito

4.用BDDMockito进行模拟

Let’s try to test the PhoneBookService where we’ll need to mock the PhoneBookRepository:

让我们试着测试一下PhoneBookService,我们需要模拟PhoneBookRepository:

public class PhoneBookService {
    private PhoneBookRepository phoneBookRepository;

    public void register(String name, String phone) {
        if(!name.isEmpty() && !phone.isEmpty()
          && !phoneBookRepository.contains(name)) {
            phoneBookRepository.insert(name, phone);
        }
    }

    public String search(String name) {
        if(!name.isEmpty() && phoneBookRepository.contains(name)) {
            return phoneBookRepository.getPhoneNumberByContactName(name);
        }
        return null;
    }
}

BDDMockito as Mockito allows us to return a value that may be fixed or dynamic. It’d also allow us to throw an exception:

BDDMockito因为Mockito允许我们返回一个可能是固定的或动态的值。它还允许我们抛出一个异常。

4.1. Returning a Fixed Value

4.1.返回一个固定的值

Using BDDMockito, we could easily configure Mockito to return a fixed result whenever our mock object target method is invoked:

使用BDDMockito,我们可以轻松地配置Mockito,使其在我们的模拟对象目标方法被调用时返回一个固定的结果。

given(phoneBookRepository.contains(momContactName))
  .willReturn(false);
 
phoneBookService.register(xContactName, "");
 
then(phoneBookRepository)
  .should(never())
  .insert(momContactName, momPhoneNumber);

4.2. Returning a Dynamic Value

4.2.返回一个动态值

BDDMockito allows us to provide a more sophisticated way to return values. We could return a dynamic result based on the input:

BDDMockito允许我们提供一种更复杂的方式来返回值。我们可以根据输入来返回一个动态的结果。

given(phoneBookRepository.contains(momContactName))
  .willReturn(true);
given(phoneBookRepository.getPhoneNumberByContactName(momContactName))
  .will((InvocationOnMock invocation) ->
    invocation.getArgument(0).equals(momContactName) 
      ? momPhoneNumber 
      : null);
phoneBookService.search(momContactName);
then(phoneBookRepository)
  .should()
  .getPhoneNumberByContactName(momContactName);

4.3. Throwing an Exception

4.3.抛出一个异常

Telling Mockito to throw an exception is pretty straightforward:

告诉Mockito抛出一个异常是非常直接的。

given(phoneBookRepository.contains(xContactName))
  .willReturn(false);
willThrow(new RuntimeException())
  .given(phoneBookRepository)
  .insert(any(String.class), eq(tooLongPhoneNumber));

try {
    phoneBookService.register(xContactName, tooLongPhoneNumber);
    fail("Should throw exception");
} catch (RuntimeException ex) { }

then(phoneBookRepository)
  .should(never())
  .insert(momContactName, tooLongPhoneNumber);

Notice how we exchanged the positions of given and will*, that’s mandatory in case we’re mocking a method that has no return value.

注意我们如何交换了givenwill*的位置,这是必须的,因为我们要模拟一个没有返回值的方法。

Also notice that we used argument matchers like (any, eq) to provide a more generic way of mocking based on criteria rather than depending on a fixed value.

还注意到,我们使用了参数匹配器,如(any,eq),以提供一种更通用的基于标准的嘲弄方式,而不是取决于一个固定的值。

5. Conclusion

5.结论

In this quick tutorial, we discussed how BDDMockito tries to bring a BDD resemblance to our Mockito tests, and we discussed some of the differences between Mockito and BDDMockito.

在这个快速教程中,我们讨论了BDDMockito如何试图为我们的Mockito测试带来BDD的相似性,我们还讨论了MockitoBDDMockito之间的一些区别。

As always, the source code can be found over on GitHub – within the test package com.baeldung.bddmockito.

一如既往,源代码可以在GitHub上找到–在测试包com.baeldung.bddmockito中。