单元测试的目的是在不涉及依赖的情况下测试代码(隔离)。

Target and challenge of unit testing

Unit test 目标是针对一个模块或者一段代码隔离测试,应该消除其他类,或者系统依赖带来的副作用。

测试替身(Test Doubles)用来消除这类副作用,test Doubles 可以分为:

  • dummy object 传入不使用
  • fake object 有基本实现,但是非常简单,比如内存数据库
  • stub class 带着特殊目的的接口或者类的部分实现
  • mock object 接口或者类的虚假实现,可以用来定义固定的输出,mock object 在测试中用来执行特定的行为

通常情况下可以通过手工代码来 mock objects 或者使用 mock framework 来模拟类的行为。Mockito 是一个非常流行的 Mock framework,使用 Mockito 的三段论:

  • Mock 外部依赖,插入 mock 代码
  • 执行 unit test
  • 验证输出

Maven

http://search.maven.org 中搜索 a:"mockito-core" 或者 g:"org.mockito"

启用注解

第一种方法,使用 JUnit 的 @RunWith

@RunWith(MockitoJUnitRunner.class)
public class MockitoAnnotationTest {
    ...
}

或者用代码启用

@Before
public void init() {
    MockitoAnnotations.initMocks(this);
}

@Mock 注解

最常用的注解就是 @Mock 注解,使用 @Mock 注解来创建和插入 mocked 实例,这样就省去了手动调用 Mockito.mock() 方法。

@Spy 注解

@Spy 注解可以 mock 真实对象的方法,让真实对象方法被调用时,就像 mock object 一样可以被配置。

@Captor 注解

参数捕获器,用于捕获 mock 方法参数,进行验证使用

@InjectMocks 注解

@InjectMocks 注解会自动将 mock fields 注入到被测试的 object 中。

when thenReturn

通过 when().thenReturn() 方法链可以用来指定一个方法调用预先定义好的返回值。这个方法也可以指定抛出一个异常

Properties properties = mock(Properties.class);

when(properties.get(”Anddroid”)).thenThrow(new IllegalArgumentException(...));

try {
    properties.get(”Anddroid”);
    fail(”Anddroid is misspelled”);
} catch (IllegalArgumentException ex) {
    // good!
}

thenReturn vs thenAnswer 区别

当 mock 方法是知道确定的返回值,那么可以使用 thenReturn 或者 doReturn,方法会 mock 一个确定的返回值。

thenReturn(T value) Sets a return value to be returned when the method is called.

Answer 当需要根据不同条件来 mock 方法并且返回不同返回值时需要 Answer,比如需要根据方法传入参数来返回对应的返回值的情况。

reference