Mockito

Mockito是一个Java平台的开源单元测试框架列表，在MIT许可证下发布。该框架允许在自动化单元测试中创建测试替身对象（模拟对象），用于测试驱动开发（TDD）或行为驱动开发（BDD）。

该框架的名称和图标是对莫吉托（Mojito，一种饮料）的模仿。

## 特点

Mockito允许开发人员验证被测系统（SUT）的行为，而无需事先建立期望。对于模拟对象，有人批评其测试代码与被测系统的紧耦合。Mockito试图通过取消期望规范，来摆脱“期望-运行-验证”的模式。Mockito还提供了一些用于减少样板代码的注解。

## 起源

Mockito是从扩展EasyMock的语法和功能开始的。

## 例子

下面是一个非耦合的Hello world程序；我们可以对它的某些部分进行单元测试，对其它部分使用模拟对象。

```java
package org.examples;

import java.io.IOException;

public class HelloApplication {

   public static interface Greeter {
      String getGreeting(String subject);
      String getIntroduction(String actor);
   }
   
   public static class HelloGreeter implements Greeter {
      private String hello;
      private String segmenter;
      
      public HelloGreeter(String hello, String segmenter) {
         this.hello = hello;
         this.segmenter = segmenter;
      }
      public String getGreeting(String subject) {
         return hello + " " + subject; 
      }
      public String getIntroduction(String actor) {
         return actor+segmenter;
      }
   }
   
   public static interface HelloActable {
      void sayHello(String actor, String subject) throws IOException;
   }
   
   public static class HelloAction implements HelloActable {
      private Greeter helloGreeter;
      private Appendable helloWriter;

      public HelloAction(Greeter helloGreeter, Appendable helloWriter) {
         super();
         this.helloGreeter = helloGreeter;
         this.helloWriter = helloWriter;
      }
      public void sayHello(String actor, String subject) throws IOException { 
         helloWriter.append(helloGreeter.getIntroduction(actor)).append(helloGreeter.getGreeting(subject));
      }
   }

   public static void main(String... args) throws IOException {
      new HelloAction(new HelloGreeter("hello", ": "), System.out).sayHello("application", "world");
   }

}
```

启动HelloApplication后，结果如下：

```
application: hello world
```

HelloActable组件的单元测试可能如下：

```java
package org.examples;

import static org.mockito.Matchers.any;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

import org.junit.Before;
import org.junit.Test;

import org.examples.HelloApplication.HelloActable;
import org.examples.HelloApplication.HelloAction;
import org.examples.HelloApplication.Greeter;

public class HelloActionUnitTest {
   
   Greeter helloGreeterMock;
   Appendable helloWriterMock;
   HelloActable helloAction;
   
   @Before
   public void setUp() {
      helloGreeterMock = mock(Greeter.class);
      helloWriterMock = mock(Appendable.class);
      helloAction = new HelloAction(helloGreeterMock, helloWriterMock);
   }
   
   @Test
   public void testSayHello() throws Exception {
      when(helloWriterMock.append(any(String.class))).thenReturn(helloWriterMock);
      when(helloGreeterMock.getIntroduction(eq("unitTest"))).thenReturn("unitTest : ");
      when(helloGreeterMock.getGreeting(eq("world"))).thenReturn("hi world");
      
      helloAction.sayHello("unitTest", "world");
      
      verify(helloGreeterMock).getIntroduction(eq("unitTest"));
      verify(helloGreeterMock).getGreeting(eq("world"));

      verify(helloWriterMock, times(2)).append(any(String.class));
      verify(helloWriterMock, times(1)).append(eq("unitTest : "));
      verify(helloWriterMock, times(1)).append(eq("hi world"));
   }
}
```

它为Greeter和Appendable接口使用了模拟对象，并隐式假设了下一个用例：

```
unitTest : hi world
```

用于测试Greeter与HelloActable联合在一起的集成测试代码可能如下：

```java
package org.examples;

import static org.mockito.Matchers.any;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

import org.junit.Before;
import org.junit.Test;

import org.examples.HelloApplication.HelloActable;
import org.examples.HelloApplication.HelloAction;
import org.examples.HelloApplication.Greeter;
import org.examples.HelloApplication.HelloGreeter;

public class HelloActionIntegrationTest {
   HelloActable helloAction;
   Greeter helloGreeter;
   Appendable helloWriterMock;
   
   @Before
   public void setUp() {
      helloGreeter = new HelloGreeter("welcome", " says ");
      helloWriterMock = mock(Appendable.class);
      helloAction = new HelloAction(helloGreeter, helloWriterMock);
   }
   
   @Test
   public void testSayHello() throws Exception {
      when(helloWriterMock.append(any(String.class))).thenReturn(helloWriterMock);

      helloAction.sayHello("integrationTest", "universe");

      verify(helloWriterMock, times(2)).append(any(String.class));
      verify(helloWriterMock, times(1)).append(eq("integrationTest says "));
      verify(helloWriterMock, times(1)).append(eq("welcome universe"));
   }
}
```

它仅使用模拟对象代替Appendable接口，而使用其它（HelloActable和Greeter）接口的真实实现，并隐式假设了下一个用例：

```
integrationTest says welcome universe
```

从HelloActionUnitTest和HelloActionIntegrationTest这两个类的import语句可以看出，需要在类路径中加入一些Mockito和JUnit的包才能编译和运行测试类。

## 基本资料

- 开发者：斯蒂芬·费伯（Szczepan Faber）、布莱斯·杜泰尔（Brice Dutheil）、拉斐尔·温特哈特（Rafael Winterhalter）、蒂姆·范德利普（Tim van der Lippe）等
- 编程语言：Java
- 类型：测试
- 许可协议：MIT许可证