声明:
Author:赵志乾
Date:2017-8-5
Declaration:All Right Reserved!!!
1、JMockit库中的ExpectationsAPI提供了测试用例编写时对模拟的支持。测试过程中,使用mocking的关注点在于所测代码同其所依赖部分的交互呈现出预期行为。一般而言,一个单元的行为被封装在一个类中,当然,我们也可以将一系列强相关的类作为单元测试中的一个被测单元。
并不推荐将单个方法作为一个单独的测试单元,因为这样做纯属是为了提高代码的覆盖率。故此,我们并不推荐严格意义上的单元测试,也不应该去mock每一个依赖类。即只有当无法使用真正的实现或者使用mock能够简化我们的测试时,才去使用模拟。
2、两个类之间的交互通常表现为方法和构造函数的调用。被测类对其依赖方法的一系列调用一般会伴随着参数和返回值得传递。此外,也可能需要验证这一系列调用的相对顺序。
3、mock的目标是对被测代码对其依赖组件的方法和构造函数的调用进行模拟,从而将被测代码从系统中分离出来。这种模拟方法有如下两类:
mock字段:通过注解将依赖声明为测试类的实例字段;
mock参数:通过注解将依赖声明为测试方法的传入参数;
这两类形式是等效的。且被mock的类型可以是任意的引用类型:接口、抽象类、final类、注解以及枚举。默认情况下,测试期间mock的类型的所有非私有化方法均会被mock。如果mock的类型是一个类,则它的超类也会递归地被mock。因此,继承的方法也会被mock。对于一个类而言,它的非私有化构造函数也会被mock。
4、当一个方法或构造函数被mock后,测试期间它原来的实现将不再起作用。即调用会被重定向到JMockit,从而表现出我们预定义的行为特性。下面给出一个测试结构的示例来说明mock字段和mock参数以及他们在测试代码中的典型使用方式。
// "Dependency" is mocked for all tests in this test class.
// The "mockInstance" field holds a mocked instance automatically created for use in each test.
@Mocked Dependency mockInstance;
@Test
public void doBusinessOperationXyz(@Mocked final AnotherDependency anotherMock)
{
...
new Expectations() {{ // an "expectation block"
...
// Record an expectation, with a given value to be returned:
mockInstance.mockedMethod(...); result = 123;
...
}};
...
// Call the code under test.
...
new Verifications() {{ // a "verification block"
// Verifies an expected invocation:
anotherMock.save(any); times = 1;
}};
...
}
测试方法被执行时,位于测试方法参数列表中的mock参数,会被JMockit自动创建和初始化,所以mock参数永远不会为null;而对于mock字段的实例,其也会被JMockit自动创建和赋值。
注:本博客中的实例代码均来自于JMockit官方教程。