Spock Primer 翻译

起因

最近要搞groovy介绍,准备做成一系列的东西,参考github上的计划。
https://github.com/javahub/groovy_hello

spock没有找到翻译文档,动手把最重要的一章primer翻译下,想起了c++ primer。
就当作翻译练习了。

目前项目大使用spock做测试,也是比较推荐的方式。简洁清爽

Spock Primer

这一章假设你有关于groovy与单元测试基本知识。如果你是java开发者,但没听说过groovy,别担心,groovy对java开发者来说非常友好。事实上,groovy相关抓哟设计目标是与java共存脚本语言。因此只需要继续并查看groovy doc

这一章目标是教会你足够写真实spec的spock,并且激起你的食欲

学习更多关于groovy,点http://groovy-lang.org/.

学些更多关于单元测试,点 http://en.wikipedia.org/wiki/Unit_testing.

术语

让我们开始一些定义:spock 让你写描述期望特性展示spec作为系统关注点,系统感兴趣关注点可以是一个简单的类和整个系统中的任何事,并且被称为spec下的系统(sus)。一个特性描述开始于spec sus的临时快照并且作为一个合作者。快照被称作特性fixture

接下来的部分沿着在spock的spec可能组合构建blocks。一个常规spec能使用它们的中一部分。

Specification

一个spec表现为继承spock.lang.Specification的一个groovy 类。spec名字通常描述系统或系统操作。例如: CustomerSpec, H264VideoPlayback, and ASpaceshipAttackedFromTwoSides是一个规范合理的名称

spec类包含一系统有用的方法,此处它含义为spec用Sputnik在junit中运行,spock的junit runner,感谢Sputnik,spock spec能运行在大多数的ides和构建工具

Fields

def obj = new ClassUnderSpecification()
def coll = new Collaborator()

对象实例字段是一个好的地方去存储属于spec fixture 。它是一个好的实践在正确初始化他们在定义时候。(语义上它等价于初始化他们在setup()方法).存储这些实例字段的对象不应该分享在feature方法之间。取而代之,每个特性方法得到他们自己的初始化对象。这个帮助在相互间独立隔离特性方法,提供一个好的目标。

@Shared res = new VeryExpensiveResource()

一些时候你需要分享一个对象在特性方法之间。例如对象可能创建很昂贵,或者你可能想在不同特性方法指南交互。为了实现这一点,定义@Shared 字段,它最好事初始化正确字段在一个定义点(语义上等价等价与setupSpec)

static final PI = 3.141592654

静态字段应该是常量,宁一方面shared字段是完美的,因为他的语义表现了更好的定义。

Fixture Methods

Fixture Methods
def setup() {}          // run before every feature method
def cleanup() {}        // run after every feature method
def setupSpec() {}     // run before the first feature method
def cleanupSpec() {}   // run after the last feature method

fixture方法负责在环境设置清理在每个特性方法运行。通常它是一个好的idea使用刷新fixture 方法在为每个fixture方法,在setup() and cleanup() 做这个。偶尔对特性方法分享是由意义的。他实现了分享使用shared字段与setupSpec() and cleanupSpec() methods。
所有fixture方法都是可选择的。

说明:setupSpec cleanupSpec 方法不能饮用实例字段

Feature Methods

def "pushing an element on the stack"() {
// blocks go here
}

Feature 方法是一个spec核心,他描述了你期待系统的在sus下的特性集。根据约定,特性方法呗命名字符串常量。试着为你的特性方法选择一个好的方法。并且随心使用你喜欢的特性。

概念,一个特性方法包括四个语义段:
设置特性的fixture
提供sus的刺激
描述系统期待的结果
清理fixture

Blocks

spock实现支持每个feature方法概念语法阶段作为一个特性方法。对结束来说,特性方法被构建为一个叫做blocks。blocks开始于一个label并且扩展开始下一个label或者方法结束。这个有六个blocks:setup, when, then, expect, cleanup, and where blocks.。任何语句在方法开始与第一次
隐含的setup block之间。

一个特性方法必须至少一个清晰的label,实际上,一个直接的block表现。Blocks 决定一个方法不同部分并且不能嵌套。

Blocks2Phases
这个右侧图片展示block如何匹配一个特性方法语法概念。那里的block有一个特殊的角色,被简单的展现出来,但首先让我们有一个近距离查看这个block

Setup Blocks

setup:
def stack = new Stack()
def elem = "push me"

这个setup block 你能做任何你想setpup工作为你想描述的特性。他可能不能被前面其他block处理,并且不能重复。一个setup block 没有任何特殊的语义。setup: label时可选的并被提交。结果在一个直接设置的block。given: label是一个setup的别名,并且一些时候导致更多的刻的特性方法描述。

When and Then Blocks

when与then blocks
when: //刺激
then://响应

when与then blocks 一直一起出现。他们描述一个刺激发生并响应期待。
when blocks能包含任意代码;
then blocks被禁止使用在条件,异常条件,交互与变量定义。
一个特性方法可能匹配多个when-then 块

Conditions

Conditions被描述为一个期待的状态,必须像junit的assertions。然而,conditions被写做一个描述布尔表达式,消除为必需的assertion API(恰恰更多的是一个条件呗处理为一个非布尔表达式,将会被作为处理根据groovy truth)让我们来看一些场景在以下


stack.size() == 2
|     |      |
|     1      false

尽可能保持在每个小特性方法里的条件数量。一到五个是一个好的指导。如果你有更多,你得问自己,如果在一个场景下有多个不相关的特性被提及。答案如果是yes,在几个小的特性方法重构。如果你的场景时只有不同的值,考虑使用数据表驱动(spock带有这个特性)

如果一个条件没通过,spock提供什么样的反馈。让我们试并改变第二个场景

如你所见,spock在一个场景执行期间,捕获所有值处理在,并在一个容易理解的形式表现他们。干得漂亮,不是么?

Implicit and explicit conditions

场景必须有一个 then blocks and expect blocks其中之一。出了调用空方法雨归类表达式作为交互,所有顶级表达式在这些块里面是隐含作为场景对待。在别的地方使用题哦安,你需要设计他们使用groovy的assert关键字。

def setup() {
stack = new Stack()
assert stack.empty
}

如果显试条件被触发,他将处理一些相同的诊断信息作为隐含条件。

Exception Conditions

异常场景呗使用描述作为一个when 语句块应该抛出一个异常。他们被定义使用 thrown()方法,被传递期待的异常类型。例如,描述被弹出一个空stack 应该抛出EmptyStackException,你能像下面这样写


when:
stack.pop()then:
thrown(EmptyStackException)
stack.empty

如你所见,异常场景可能是跟别的场景相关。这个特别有用为对详细说明期待内容作为异常,访问这个异常,首先绑定一个变量。


when:
stack.pop()then:
def e = thrown(EmptyStackException)
e.cause == null

宁外,你也可以使用上面语法作为一个轻微有变化


when:
stack.pop()then:
EmptyStackException e = thrown()
e.cause == null

这个语法有两个小优势,首先,异常变量时强类型,让它非常容易被ide补全。其次,场景读起来有一点更像句子。注意,如果没有异常类型被传递在thrown方法,它从左边的变量类型被推断

一些时候我们需要表达一个异常不应该被抛出。例如,让我们尝试表达hashmap不应该接受null key。

def "HashMap accepts null key"() {setup:def map = new HashMap()map.put(null, "elem")
}

一些时候我们需要表达一个异常不应该被抛出。例如,让我们尝试表达hashmap不应该接受null key。

这个表示不能揭示代码的含义。 是否有人离开构建之前就完成实现了这个方法。毕竟,场景在哪里? 幸运是我们能做更好。


def "HashMap accepts null key"() {setup:
def map = new HashMap()when:map.put(null, "elem")then:notThrown(NullPointerException)
}

通过使用notThrown。我们能使清晰在一个特殊的NullPointerException 不应该被抛出。(按照Map.put()方法的约定,它是正确的事情不支持null keys在map上使用。)然而,方法将会失败如果有任何逼的异常抛出。

Interactions

尽管条件描述了一个对象的状态,交互描述了对象互相间关系。交互被转用于一章。所以我们只快速给一个例子在这。假设我们想描述从一个发布者到订阅者的事件流。代码如下

def "events are published to all subscribers"() {def subscriber1 = Mock(Subscriber)def subscriber2 = Mock(Subscriber)def publisher = new Publisher()publisher.add(subscriber1)publisher.add(subscriber2)when:
publisher.fire("event")then:
1 * subscriber1.receive("event")
1 * subscriber2.receive("event")

Expect Blocks

一个expect block 比then block有更多的限制。他可能包含场景与变量定义。它是有用的情形当他更加自然描述刺激与期待结果响应在一个简单的表达式里。例如,比较下面两个描述 Math.max()方法。

    when:def x = Math.max(1, 2)then:x == 2expect:Math.max(1, 2) == 2

尽管两个片段时语义等价。第二个是更清晰选择。作为一个指引,使用when-then 去描述带有副作用。并且期待描述纯碎的函数方法。

TIP

利用groovy jdk方法像any() every()去创建更多表现力与简洁的条件。

Cleanup Blocks

setup:
def file = new File("/some/path")
file.createNewFile()
// ...
cleanup:
file.delete()

cleanup block

只能跟着where block后面。并且不能重复。像一个cleanup 方法,它作为释放资源使用作为一个特性方法使用,运行即使特性方法抛出异常。因此,cleanup block 必须防御编程。在最糟糕的情况下,它必须优雅的处理在特性方法里抛出异常的第一个语句。并且所有本地变量有默认值。

TIPS

groovy的安全引用操作精简写防御是代码
对象级别的spec 通常不用cleanup方法。作为唯一资源他们消费内存,自动被回收通过垃圾收集齐。更多粗力度spec,但是,可能使用clean 块 清理文件系统关闭数据库连接,关闭网络服务

def "computing the maximum of two numbers"() {
expect:
Math.max(a, b) == cwhere:
a << [5, 3]
b << [1, 9]
c << [5, 9]

}
This where block effectively creates two "versions" of the feature method: One where a is 5, b is 1, and c is 5, and another one where a is 3, b is 9, and c is 9.

这个where 块创建两个版本特性方法非常有效:One where a is 5, b is 1, and c is 5, and another one where a is 3, b is 9, and c is 9.

where block 将会在数据驱动测试章节解释

Helper Methods

一些时候特性方法增长巨大在 and/or包含重复代码。在这种情形下引入一个多个帮助方法会有意义。两个好的候选者为帮助方法是setup/cleanup 逻辑与复杂场景。分解出前者是直接的,让我们看下场景

def "offered PC matches preferred configuration"() {
when:
def pc = shop.buyPc()then:
pc.vendor == "Sunny"
pc.clockRate >= 2333
pc.ram >= 4096
pc.os == "Linux"

}
如果碰巧你也是电脑极客,你更愿意pc配置是详细的,或者你可能想比较供应从同的商店。因此,让我们分解条件


def "offered PC matches preferred configuration"() {
when:
def pc = shop.buyPc()then:
matchesPreferredConfiguration(pc)

}

def matchesPreferredConfiguration(pc) {
pc.vendor == "Sunny"
&& pc.clockRate >= 2333
&& pc.ram >= 4096
&& pc.os == "Linux"

}
新的帮助方法matchesPreferredConfiguration 由简单的布尔表达式组成作为结果返回。
这是好的除了那些一个不充分的供应被描述。

Condition not satisfied:matchesPreferredConfiguration(pc)
|                             |
false                         ...
Not very helpful. Fortunately, we can do better:void matchesPreferredConfiguration(pc) {assert pc.vendor == "Sunny"assert pc.clockRate >= 2333assert pc.ram >= 4096assert pc.os == "Linux"
}

不是很有什么帮助。幸运的事,我们可以做更好
当在一个帮助方法分解场景时,必须思考两个点:首先,隐含条件必须转换为显性条件使用assert关键字。其次,帮助方法必须返回空类型。否则,spock会解释返回值为失败条件,这并不是我们想要的。

作为猜想,改进的帮助方法告诉我们确切什么是错的。

Condition not satisfied:assert pc.clockRate >= 2333|  |         ||  1666      false...

条件不是满意:

最后一个建议:尽管重用代码是一个好事情,但不要是他太远。更聪明使用fixture 和帮助方法能增加耦合在特性方法间。如果你重用太多或者有错误代码,你将以脆弱和艰难改进的spec结束。

Specifications as Documentation

写得好的spec作为一个源码信息价值点。尤其是对高级别spec目标是更广泛的受众不知是开发者(架构师 领域专家 客户等)它是有道理的提供更多信息使用自然语言比只是使用规格与特性的名称。因此,spock提供了一种方式附属文本话的描述使用块。

setup: "open a database connection"// code goes hereIndividual parts of a block can be described with and::setup: "open a database connection"// code goes hereand: "seed the customer table"// code goes hereand: "seed the product table"

一个and 标签 跟着描述能插入到特性方法的任何位置,没有改变方法语义。

在行为驱动测试,面向客户的特性被描述在一个given-when-then 格式。spock直接支持这个风格的spec使用given标签


given: "an empty bank account"// ...when: "the account is credited $10"// ...then: "the account's balance is $10"// ...As noted before, given: is just an alias for setup:.

作为之前的提示,given知识setup的一个别名

块描述不应该出现在源码里。但应该在运行时可用对spock运行时。块描述用法的计划被增强诊断信息并且文本化的报告被所有利益相关者同样理解。

扩展
如所见,spock提供许多写spec功能。然而总是有这种时候,当一些别的东西被需要。因此,spock提供了一个基于拦截的扩展机制。扩展通过注解被直接激活。当前,spock附带一下指令

@Timeout  
Sets a timeout for execution of a feature or fixture method.设置超时时间为特性方法或者fixture方法@Ignore 
Ignores a feature method.忽略特性方法@IgnoreRest 
Ignores all feature methods not carrying this annotation. Useful for quickly running just a single method.
不移除这个注释,忽略所有特性方法不去。对快速运行单个方法非常有用。

期待一个特性方法去完成打断。@FailsWith有两个用例:首先,文档化我们知道的bug不需要立刻解释。其次,替换异常条件在一个确定的角落用例在后面不能使用。在所有的用例,异常条件不是优选。

学习怎样实现你自己的指令与扩展,去看扩展章节

Comparison to JUnit

尽管spock使用不同的技术,大部分概念和特性呗激活从junit。这有一个粗的比较
comparison

|Spock|JUnit|
|--|--|
|Specification|Test class|
|setup()|@Before|
|cleanup()|@After|
|setupSpec()|@BeforeClass|
|cleanupSpec()|@AfterClass|
|Feature|Test|
|Feature method|Test method|
|Data-driven feature|Theory|
|Condition|Assertion|
|Exception condition|@Test(expected=…​)|
|Interaction|Mock expectation (e.g. in Mockito)|

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/262301.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

location 拦截所有_让它帮你干掉所有流氓软件,还你一个清静系统

最近大家应该都要复工了吧&#xff01;我们又到了捧着电脑跑来跑去的日子&#xff0c;不过相比在家&#xff0c;复工还是蛮激动的。今天队长聊一下电脑软件。电脑这种东西&#xff0c;现在虽算不上是生命之源&#xff0c;但是复工上班工作或者交作业的时候那可真是当祖宗供着的…

grub4dos和winsetupfromusb1.4

其实grub4dos也是一个多系统启动盘制作软件&#xff0c;GRUB4DOS 最大的成功之处就是既学习了windows的方便易用&#xff0c;又引入linux的强大功能。http://baike.baidu.com/link?urlvFkYDEOTmdnw0dLueYeNz0V48egdnjpHczS3YwWiSsXtM7krYaE6KiDohCT4hlo5-LihtQU7fYhXuURazx_OK…

一份完整的问卷模板_一份完整市场推广策划方案模板

完整的市场方案主要分为以下几大板块&#xff0c;在策略撰写的过程中&#xff0c;依据策略优先级按照以下三个步骤划分&#xff0c;前后承接。为避免无用功&#xff0c;尽量确定前一部分后&#xff0c;再开始后一部分&#xff01;方案目录&#xff0c;记住这个&#xff01;整个…

Application是什么

2019独角兽企业重金招聘Python工程师标准>>> 1:Application是什么&#xff1f; Application和Activity,Service一样,是android框架的一个系统组件&#xff0c;当android程序启动时系统会创建一个 application对象&#xff0c;用来存储系统的一些信息。通常我们是不需…

linux mysql udf打包_Linux下MySQL 5.1编写UDF 并运行(Install)获取当前时间的毫秒数...

Mysql 无法获取当前时间的毫秒数自行定制UDF&#xff0c;以提供current_ms方法1. 编写 C 文件#ifdef STANDARD#include lt;stdio.hgt;#incMysql 无法获取当前时间的毫秒数自行定制UDF&#xff0c;以提供current_ms方法1. 编写 C 文件#ifdef STANDARD#include #include #ifdef _…

Daily Scrum 2012/11/08

TeamSH-IT 今天经完成了之前在数据定义存在一些问题。sui老师经过小组之间的交流&#xff0c;完成了对数据定义的最终版。周末将进行初步的整合和测试。 详细的完成情况&#xff1a; 组员今天任务明天任务Hu Renjun 任务213 整合各个模块功能 完成完整的数据流过程 任务213 …

部分不能激活Win 7 的问题分析和解决方案

前言 总所周知&#xff0c;目前Win7的激活程序多如牛毛&#xff0c;但总有些朋友的机器就是激活不了&#xff0c;以至于要刷BIOS等高危操作。 本文通过对Win7激活程序的原理分析&#xff0c;介绍一种能够解决大部分OEM版系统激活Win7的方法&#xff0c;希望能够帮助需要的朋友…

MFC字体

GDI字体分3类&#xff1a;点阵字体&#xff08;raster font&#xff09;、笔画字体&#xff08;stroke font&#xff09;和Truetype字体。 默认点阵字体有7种&#xff1a; System &#xff08;用于SYSTEM_FONT&#xff09; 无衬线 西方 有衬线 gb2312…

decimal double java_Java BigDecimal和double BigDecimal类

BigDecimal类对于不需要任何准确计算精度的数字可以直接使用float或double&#xff0c;但是如果需要精确计算的结果&#xff0c;则必须使用BigDecimal类&#xff0c;而且使用BigDecimal类也可以进行大数的操作。BigDecimal类的常用方法如表11-15所示。表11-15 BigDecimal类的常…

分享45套2011年和2012年的高质量免费网站模板

日期&#xff1a;2012-11-11 来源&#xff1a;GBin1.com 前端时间我们分享了12套超酷的后台管理员界面网站模板&#xff0c;相信看过的朋友肯定已收入囊中了&#xff0c;今天呢&#xff0c;我们继续推荐45套高质量的免费网站模版&#xff0c;相信如果需要自己搭建网站的朋友肯…

水晶报表中对某一栏位值进行处理_【节能学院】能耗管理系统在某超市嘉兴店二期工程的设计与应用...

摘要&#xff1a;随着社会生活水平的提高&#xff0c;经济的繁荣发展&#xff0c;人们对能源的需求逐渐增长&#xff0c;由此带来的能源危机日益严重。学校建筑如何实时的了解、分析和控制学校的能源消耗已成为需要解决的迫在眉睫的难题。传统的能源消耗智能以月/季度/年为周期…

python数据分析天气预报论文_用python+sklearn(机器学习)实现天气预报数据 模型和使用...

项目地址系列教程0.前言在上一篇教程里我们已经获取了所需要的全部数据&#xff0c;包括训练数据集和测试数据集&#xff0c;使用ProcessData()调用&#xff0c;所以接下来写模型的建立和预测1.建立模型没段代码在文章后面都会整合成一段&#xff0c;分段展示只是便于阅读a.准备…

偶然在网上看到的题目,jQuery功底如何一测便知晓!!!!!!

笔者最终实现的效果如下&#xff1a;    参考答案下载地址 通过手写html代码实现如图效果&#xff1a;以下题目全部使用jQuery来做 当点击“加载数据”按钮时根据提供的数据通过jQuery动态创建表格数据填充该表格。数据见data.txt文件。效果如图&#xff1a; 当点击“设置样…

ps作业素材和成品_没有用过PS的画框工具,你还敢说你是设计大佬?

大家好&#xff0c;过完春节大伙们都踏上了离乡的征程&#xff0c;再多不舍&#xff0c;看看自己的钱包&#xff0c;还是要出发&#xff01;2019年已经悄然过去一个半月&#xff0c;你的学习计划开始了嘛&#xff1f;来吧继续学习PS-cc2019,今天继续给大家带来CC2019 ps 的基础…

第二次阅读作业

No Silver Bullet - Essence and Accidents of Software Engineering&#xff1a; 银弹能杀死狼人。如果我没记错的话&#xff0c;在漫画中柯南对黑暗组织而言就是一颗银弹。生活中是不是真的有银弹我还是不太确定。假如有&#xff0c;银弹就是 一点弱点也没有么&#xff1f;如…

Linux 每日一练习!!反单引号·(键盘上数字1左边)··

2019独角兽企业重金招聘Python工程师标准>>> ls -al locate ls # 说明locate ls执行出来的路径将会作为ls -al的参数 说明&#xff1a;在一串指令中&#xff0c;在之内的指令将会被先执行&#xff0c;而且执行出来的结果将作为外部的输入信息 转载于:https://my.osc…

docker-compose观察实时日志_大数据项目实战之在线教育(03实时需求) - 十一vs十一...

第1章Spark Streaming概念 Spark Streaming 是核心Spark API的扩展&#xff0c;可实现实时数据的可扩展&#xff0c;高吞吐量&#xff0c;容错处理。数据可以从许多来源(如Kafka,Flume,Kinesis,或TCP套接字)中获取&#xff0c;并可以使用高级函数进行处理&#xff0c;处理完后的…

Java动态加载类在功能模块开发中的作用

Java中我们一般会使用new关键字实例化对象然后调用该对象所属类提供的方法来实现相应的功能&#xff0c;比如我们现在有个主类叫Web类这个类中能实现各种方法&#xff0c;比如用户注册、发送邮件等功能&#xff0c;代码如下&#xff1a; 1 /*2 * web功能实现类3 */4 public c…

创业者们的19个Surprises

郑昀玩聚SR 20091115 『毫无疑问&#xff0c;短跑运动员在起跑时速度最快&#xff0c;而后就变慢下来&#xff0c; 获胜者是变慢得最少的那个人。大多数创业公司也是如此。』 ——Paul Graham January 2007 上面这句笺言的作者Paul Graham最近问了Y Combinator旗下创业项目的创…

自学电脑编程_程序人生:盲人程序员蔡勇斌——用耳朵打开盲人的程序世界 - 沐歌爱编程...

有句话说&#xff1a;没有你想不到&#xff0c;只有你做不到。今天想为大家介绍一位程序员界中的励志人物&#xff0c;他就是蔡勇斌。蔡勇斌幼年失明&#xff0c;靠着顽强的毅力和不服输的精神自学编程&#xff0c;成为了一名全栈工程师。他是阿里“多隆奖”首位盲人获得者&…