最近一直在着力推动部门单元测试工作,发现一些不规范的地方,特此尝试翻译下用户指南,方便大家参考。
原文参考:http://code.google.com/p/jmockit/
及 http://jmockit.googlecode.com/svn/trunk/www/tutorial/BehaviorBasedTesting.html
- 前言:开发者可以借助JMockit这个强大的测试辅助工具,利用mock 的API去解决平常在单元(或者集成)
测试中遇到的常见的可测试性问题。开发者同样可以很方便快捷的对final类、静态方法或者构造函数等进行mock模拟。在Jmcokit的世界中,没有
其他任何的限制。
Jmockit的API是极致简单、易用的。在编写测试代码时,不需要在测试代码中嵌入一些特定的方法或者注解,当然不包括一些必须的、有意义的方法和注解(还是有一定的必要).一般而言,使用JMockit的mock API可以使测试代码更结构化,可读性变得更强。
public void testDoOperationAbc(final DependencyXyz mock)
{
new NonStrictExpectations() {
AnotherDependency anotherMock;
{
anotherMock.doSomething("test"); result = 123;
}
};
new ServiceAbc().doOperation("some data");
new Verifications() {{
mock.complexOperation(true, anyInt, null); times = 1;
}};
}Mocked types
在Jmockit的工具箱中,Expectations 期望和Verifications
验证API对基于行为的单元测试提供了丰富的支持。这类型的测试的焦点是当前的单元测试代码如何和其他相依赖的单元进行交互。这些行为单元可以是定义在生
产环境中的class类,method方法,以及构造函数。
两个单元之间的交互通常以方法或者构造函数调用的形式出现。以参数和返回值的形式在当前单元和被依赖的单元之间传递构成的调用集合,定义了我们感兴趣的测
试代码行为。另外,对于给定的一个测试,可能需要判定调用集合在执行期间的执行顺序。注意,一个单元测试应该只是执行可测试的单元代码。这些实现所依赖的
关系不一定需要被执行,因为这些依赖并不是当前单元测试的一部分。所以,单元测试的目标应该是测试一些业务逻辑,这些逻辑是和真实行为需要依赖的外部关系
或者环境是隔离的。现在,对于给定的单元,我们一般不需要隔离所有的依赖,但需要隔离如下这些:1)一些依赖单元本身已经(或者将来会有,只是目前还没有
实现而已)拥有自己的单元测试。2)由于一些特殊原因,在测试环境中,一些并不是很容易快速的执行的单元(因为它们可能会写数据库或者发送邮件等等)。当
我们编写一个特殊的单元测试时,我们一般假设它对外部的依赖是满足一些期望的。如果不是的话,那就是外部的依赖本身所需要负的责任了,并应该满足这些期
望。
一般来说,在单元测试代码中,方法调用、构造函数以及那些相互依赖 /协助的单元都是我们mock的目标。
Mock技术提供了一种隔离外部依赖的可测试的单元机制。我们通过使用mocked声明,可以在指定的测试代码对一些特殊的依赖进行
mock模拟,也就是说,一个mocked类型,应该是单元测试中的一个依赖类型,这些类型可以是引用、接口、抽象类、具体的类、final 类等等。
默认情况下,被mock的类型的所有方法在测试期间都被
mock实现。如果一个mock类型被声明为类,那么除了java.lang.Object之外,该类的父类将被递归mock。因此,继承的方法也将自动
被mock。同样,对于声明为类的mock类型,其所有构造函数也将被
mock。甚至,无论方法或者构造函数的修饰符是否是private,stati,final,native等,这些方法和构造函数都会被mock掉,对
于mock类型来说,修饰符的定义变得如此不重要了。
在一个测试调用中,如果当一个方法或者构造函数被mock了,则其原始的实现代码将不会被执行,取而代之的是,可以通过
jmockit显式或者隐式指定测试调用。下面的示例代码,展示了一个mock类型的基本调用图。在这个指南中,我们通常使用类似这样的代码。当然,粗体
部分的注释才是我们现在的重点。
@Test
public void doBusinessOperationXyz()
{
...
new Expectations() // 一个称为期望的结构块
{
Dependency mockInstance; // "Dependency"是我们需要mock的类型
...
{
...
// "mockInstance" 是一个mock实例,在测试代码中自动提供如下类型的mock使用方法
mockInstance.mockedMethod(...);
...
}
};
...
}
就如我们即将在下面看到的一样,这里提供了好几种方式来声明mock类型,同样提供几种特殊修饰语法以满足一些特殊的测试mock。但大多数情况
下,例如变量都是通过一些特定的注解及注解本身的属性来指定mock,例如 @Mocked, @NonStrict,
@Injectable等等。这些注解标记可以在实例的域或者测试方法的参数中使用。
- Expectations(期望)
Expectations是一个给定的单元测试相关的mock方法/构造函数的调用集合。对于一个同样的方法或者构造函数,一个Expectations
可能会覆盖到多个不同调用,但是它不需要(不一定)覆盖到单元测试方法执行期间的所有调用(invocations)。一个特定的调用是否匹配给定的
expectation,不仅依赖方法/构造函数的签名,而且依赖运行时方面参数(aspects),例如被调用的方法类实例、参数值以及调用次数等等。
因此,对于给定的expectation,可以(可选)指定几种不同类型的匹配约束。
对于具有一个或者多个参数调用的情况,可能需要对每一个参数指定精确的参数值。例如,"test
string"可以指定为一个字符串参数,从而匹配到那些具有相应的精确的参数调用的expectation。正如我们后面将所见到的一样,我们可以通过
指定更多相关的约束来匹配一个具有不同参数值的集合,而不是指定精确的参数值。
下面的例子展示了类Dependency的方法someMethod(int, String)的一个期望(expectation
),这个期望是通过指定严格(精确)的参数值来匹配这个方法的调用。值得注意的是,对于这个mock方法,这个期望本身就是一个特定的隔离调用。在测试代
码中,没有什么特殊的API的参与其中。但是,在我们所感兴趣的测试中,这个调用不能认为是一个真实的调用。它在这里的目的唯一作用是可以用于指定
expectation而已。
@Test
public void doBusinessOperationXyz()
{
...
new Expectations()
{
Dependency mockInstance;
...
{
...
// 一个mock实例的mock方法
mockInstance.someMethod(1, "test");
...
}
};
//这里应该是一个单元测试方法调用,这个调用可能匹配(也可能不匹配)上面指定的expectations
}
在之后我们理解了recording、
replaying、
verifying调用的差异后,我们将看到更多的
expectations。
- Record-Replay-Verify模型
任何一个测试至少可以划分三个相互独立的阶段,这些阶段将按顺序执行,一次执行一个阶段,例如下面的示例:
@Test
public void someTestMethod()
{
// 1. 准备阶段:测试执行之前所需要的所有东西都可以编写在这里
...
// 2. 单元测试代码在这里执行,通常是通过调用public方法来执行
...
// 3. 验证阶段:验证上面所执行的单元测试代码真正执行了其业务逻辑
...
}
首先,我们有一个准备阶段,单元测试代码所需要的对象和数据都可以在这里创建或者从其他地方加载进来。之后,测试的代码被执行。最后,测试结果和期望结果进行比较。
这个著名的三阶段也叫做Arrange, Act, Assert
语法,或者简称为"AAA",不同的词语而已,意思实际就是一样。
在基于行为的测试上下文中,通过使用 mock类型(以及他们对应的mock实例),我们可以辨别出来下面的交互流程直接对应上面描述的哪些测试阶段。
(1) Record(记录)阶段:在这里将记录下哪些调用会被期望执行,这些都是发生在测试的准备阶段,而且在真正测试代码执行调用之前。
(2) Replay(重播)阶段:我们感兴趣的mock
调用将在这里有机会被执行,就好像真正的单元测试代码被执行一样。这些在Record阶段记录下来的 mock方法
/构造函数调用将在这里重播(执行),尽管这些mock调用在record和replay阶段通常不是一对一对应的。
(3)Verify(验证)阶段:所有的真实调用应该在这里和期望值进行校验,这些动作发生在测试验证阶段。
利用JMockit工具来编写基于行为的测试代码,通常符合下面的经典模板:
import mockit.*;
... other imports ...
public class SomeTest
{
// 零个或者更多的mock 属性, 这些属性对于整个类的所有测试方法来说是通用的。
@Mocked Collaborator mockCollaborator;
@NonStrict AnotherDependency anotherDependency;
...
@Test
public void testWithRecordAndReplayOnly(mock parameters)
{
// 如果这里需要测试前的准备,可以在这里执行,但对于Jmockit 来说,对此没特别要求。当然这里也可以为空。
new Expectations() // 一个期望块
{
// 零个或者多个局部 mock 属性域
{
// 一个或者多个mock对象(类型)的调用,这些调用会被Expectations记录(Recorded)下来
//一些没有被mock的方法、对象类型等同样可以在这个期望块里面调用
}
};
// 单元测试代码真正业务逻辑在此执行
// 如果需要,可以在这里进行验证代码编写,当然可以利用JUnit/TestNG 断言
}
@Test
public void testWithReplayAndVerifyOnly(mock parameters)
{
// 如果这里需要测试前的准备,可以在这里执行,但对于Jmockit 来说,对此没特别要求。当然这里也可以为空。
// 单元测试代码真正业务逻辑在此执行
new Verifications() {{ // 一个验证块
// 一个或者多个mock对象(类型)的调用,这些调用用于验证结果是否正确
//一些没有被mock的方法、对象类型等同样可以在这个验证块里面调用
}};
// 如果需求,这里可以添加其他额外的验证代码,
// 当然,这些验证可以编写在这里,也可以在Verifications块之前
}
@Test
public void testWithBothRecordAndVerify(mock parameters)
{
//如果这里需要测试前的准备,可以在这里执行,但对于Jmockit 来说,对此没特别要求。当然这里也可以为空。
new NonStrictExpectations() { // 同样是一个期望块
//零个或者多个局部 mock 属性域
{
// 一个或者多个mock对象(类型)的调用,这些调用会被Expectations记录(Recorded)下来
}
};
// 单元测试代码真正业务逻辑在此执行
new VerificationsInOrder() {{ // 同样是一个验证块
// 一个或者多个mock对象(类型)的调用,这些调用将期望按照特定的顺序进行比较。
}};
// 如果需求,这里可以添加其他额外的验证代码,
// 当然,这些验证可以编写在这里,也可以在Verifications块之前
}
在上面的模板中,还存在一些其他额外的变量,但是从本质上来说,这些expectation
期望块是属于Record阶段的,而且在单元测试真正业务逻辑执行前被执行,当然,自然而然,verification
验证块是属于验证阶段的。一个测试方法可以包含任意数量(含零个)的期望块,验证块也是一样。
事实上,我们可以利用现代JAVA IDE工具的高级功能"代码折叠",对匿名内部类进行折叠展示。下面图片显示了再IntelliJ IDEA中的折叠效果:
分享到:
相关推荐
入门指南部分会引导用户通过基础实例熟悉JaamSim,通过实际操作学习如何启动控制台、创建和运行仿真模型。JaamSim的安装过程非常简单,只需将可执行文件复制到所需目录,双击即可运行。TLS等特定应用程序的安装与...
java平台的API规范,标准版翻译校对版本,这是好心人翻译的,我认为目前是最好的中文api,分享下信息,chm版本
**Z-stack开发指南-中文翻译-未纠错** Z-stack是由美国德州仪器(TI)提供的一种专为ZigBee无线网络设计的协议栈。ZigBee是一种基于IEEE 802.15.4标准的低功耗、低数据速率、近距离无线通信技术,广泛应用于智能...
2. "梁截面校对.gif":这可能是一个动态图像文件,展示了插件的操作过程或者结果展示,帮助用户更好地理解和使用这个工具。 3. "LAYER.lsp":这是一个LISP程序,LISP是AutoCAD支持的编程语言,用于编写自定义功能和...
- **翻译历程**: 自2009年起,OWASP测试指南中文版经历了多次翻译和修订。最初由Frank Aaron等人启动翻译项目,后续有多位志愿者参与了翻译和校对工作。 - **中文版贡献者**: 包括程琼、Frank Fan、贺佳琳等在内的多...
这份"Spring官方文档(中文翻译&人工校对)"是一份宝贵的资源,它帮助开发者准确理解Spring框架的核心概念和功能,无论你是初学者还是经验丰富的开发者,都能从中受益。 文档首先会介绍Spring的基本架构,包括其...
本篇论文主要围绕着基于深度学习的中文文本自动校对展开研究与实现,针对中文文本的语法错误校对,利用深度学习模型进行自动化的文本纠错,旨在提高文本处理的效率和准确性。 一、研究背景与意义 随着互联网的快速...
译者通过个人努力将英文指南翻译成中文,目的是为了推广和分享这个实用的内核,尽管自身并未决定在自己的系统中使用它。 翻译者的初衷是希望利用业余时间,边阅读边翻译,最终完成中文版文档。由于译者个人时间有限...
《校对能手》是一款中文文稿校对软件。可以快速对中文文档资料进行校对,检查出可能存在的差错,列出勘误表,供改稿时参考。同时,还有姓名筛查、人名地名索引自动编排、多能字词典、中文排序等功能。特别适用于快速...
《编辑助手》又名“校对能手”是一款中文文稿校对软件。在各种文稿的起草、修改、抄写、打字、排版过程中,难免出现各种差错,手工校对检查费时费力,往往还会有所遗漏。本软件针对上述问题,可以快速对中文文档资料...
黑马校对软件百度网盘下载地址,精确校对领导人姓名、职务和领导人排序错误。 精确校对涉及台湾和其他敏感的政治性错误。 即时更新的、可自定义的领导人职务库。校对插件 直接嵌入在Acrobat中校对PDF文件。可把校对...
内含S2版、PS版、Word版、WPS版、小样版、飞腾插件版和PDF插件版等9个全新的校对界面,采用超大规模词库和重点词监控等先进的校对计算技术,在校对质量、校对功能和易用性等方面都有了飞跃性的提高,达到了当前电脑...
中文文本自动校对系统的诞生,源于对大规模文本处理需求的增长,如新闻编辑、文档校对、机器翻译等领域。传统的手动校对方式效率低下,容易出错,而自动化校对则能显著提高效率,减少人为错误。 二、理论基础 1. ...
总而言之,哈萨克文字校对软件是一款专为哈萨克语用户量身打造的专业工具,它凭借先进算法和人性化设计,为用户提供了从拼写到语法,再到标点和格式的全方位校对服务。这款软件不仅仅是哈萨克语使用者的得力助手,更...
区块链分舵官方指南推荐优质英文文章到掘金翻译计划翻译计划译者教程如何参与翻译关于如何提交翻译以及后续更新的教程如何参与校对及校对的正确姿势文章掘金指南译文排版规则指北近期文章官方文档及手册年度总结...
4. "柱校对程序说明.txt":这是一个文本文件,可能包含了柱校对程序的详细介绍、安装指南和使用注意事项。 5. "柱校对 使用说明书.docx":这是柱校对程序的使用说明书,以Word文档形式提供,包含了详细的步骤和操作...