1. 简介
通过本文,我们将开始一个以mock工具包JMockit为中心的新系列。
在第一部分中,我们将讨论JMockit是什么、它的特性以及如何创建和使用mock。
后面的文章将重点关注并深入探讨其功能。
2. JMockit
2.1 概述
首先,让我们谈谈JMockit是什么:一个用于在测试中mock对象的Java框架(你可以将其用于JUnit和TestNG)。
它使用Java的检测API在运行时修改类的字节码,以动态改变它们的行为。它的一些优点是它的可表达性和开箱即用的mock静态和私有方法的能力。
也许你是JMockit的新手,但这绝对不是因为它是新的库。JMockit的开发始于2006年6月,其第一个稳定版本的发布日期为2012年12月,因此它已经存在了一段时间。
2.2 Maven依赖
首先,我们需要将jmockit依赖项添加到我们的项目中:
<dependency>
<groupId>org.jmockit</groupId>
<artifactId>jmockit</artifactId>
<version>1.41</version>
</dependency>
2.3 JMockit的可表达性
如前所述,JMockit的一个优势点是它的可表达性。为了创建mock并定义它们的行为,你只需要直接定义它们,而不是从mock API调用方法。
这意味着你不会也不需要执行以下操作:
API.expect(mockInstance.method()).andThenReturn(value).times(2);
相反,使用以下内容代替:
new Expectation() {
mockInstance.method();
result = value;
times = 2;
}
看起来它的代码虽然更多,但你可以简单地将所有三行放在一行上。真正重要的部分是,你最终不会得到一大串链式方法调用。相反,你最终会定义你希望mock在调用时的行为方式。
如果你考虑到在result = value部分你可以返回任何内容(固定值、动态生成的值、异常等),那么JMockit的表现力会变得更加明显。
2.4 记录-重播-验证模型
使用JMockit的测试分为三个不同的阶段:记录、重播和验证。
- 在记录阶段,在测试准备期间和调用我们要执行的方法之前,我们将为下一阶段要使用的所有测试定义预期行为。
- 重播阶段是执行被测代码的阶段。现在将重播先前在上一阶段记录的mock方法/构造函数的调用。
- 最后,在验证阶段,我们将断言测试的结果是我们预期的结果(并且mock的行为和使用是根据记录阶段定义的)。
通过代码示例,测试的骨架如下所示:
@Test
public void testWireframe() {
// preparation code not specific to JMockit, if any
new Expectations() ;
// execute code-under-test
new Verifications() ;
// assertions
}
3. 创建Mock
3.1 JMockit的注解
使用JMockit时,使用mock的最简单方法是使用注解。有三种用于创建mock(@Mocked、@Injectable和@Capturing)和一种用于指定被测类(@Tested)的注解。
在字段上使用@Mocked注解时,它将创建该特定类的每个新对象的mock实例。
另一方面,使用@Injectable注解,只会创建一个mock实例。
最后一个注解@Capturing的行为类似于@Mocked,但会将其范围扩展到扩展或实现带注解字段类型的每个子类。
3.2 将参数传递给测试
使用JMockit时,可以将mock作为测试参数传递。这对于专门为该测试创建一个mock非常有用,例如一些需要针对单个测试的特定行为的复杂模型对象。它会是这样的:
@RunWith(JMockit.class)
public class TestPassingArguments {
@Injectable
private Foo mockForEveryTest;
@Tested
private Bar bar;
@Test
public void testExample(@Mocked Xyz mockForJustThisTest) {
new Expectations() ;
bar.codeUnderTest();
}
}
这种通过将mock作为参数传递来创建mock的方式,而不是必须调用一些API方法,再次向我们展示了我们从一开始就在谈论的可表达性。
3.3 完整示例
在本文结束时,我们将包含一个使用JMockit进行测试的完整示例。
在此示例中,我们将测试在其perform()方法中使用Collaborator的Performer类。这个perform()方法接收一个Model对象作为参数,它将使用它的getInfo()返回一个String,这个String将被传递给Collaborator的collaborate()方法,该方法将为这个特定的测试返回true,并且该值将传递给来自Collaborator的receive()方法。
因此,测试的类将如下所示:
public class Model {
public String getInfo() {
return "info";
}
}
public class Collaborator {
public boolean collaborate(String string) {
return false;
}
public void receive(boolean bool) {
// NOOP
}
}
public class Performer {
private Collaborator collaborator;
public void perform(Model model) {
boolean value = collaborator.collaborate(model.getInfo());
collaborator.receive(value);
}
}
测试的代码最终将如下所示:
@RunWith(JMockit.class)
public class PerformerTest {
@Injectable
private Collaborator collaborator;
@Tested
private Performer performer;
@Test
public void testThePerformMethod(@Mocked Model model) {
new Expectations() ;
performer.perform(model);
new Verifications() ;
}
}
4 总结
至此,我们将结束对JMockit的实用介绍。如果你想了解更多关于JMockit的信息,敬请期待后续文章。
与往常一样,本教程的完整源代码可在GitHub上获得。
4.1 系列文章
该系列的所有文章: