在行为驱动开发(BDD)的开发过程中,Rspec是一个编写人类可读规范的非常有用的工具,可以指导和验证应用程序的开发。网络上有很多资源可以让你完全了解RSpec的功能,却很少有资源介绍如何编写高质量的Rspec测试套件。Better Specs项目过收集“最佳实践”(大多数开发人员需要通过数年才学习到的经验)来填补这个空白。
感谢开源
在工作和学习测试Lelylan(一种用Ruby和Node.js编写的用于物联网的开源微服务体系结构)时遇到了Better Specs。尽管源代码有些过时,但仍有很好的借鉴作用。如果Better Specs 帮到了你,请在Github上给我们star(以便让这个项目被更多的开发者看到),或者为Lelylan项目做贡献。
如何描述你的方法
请确保你清楚地知道你所描述的方法。例如,在Ruby文档的编写习惯中,当涉及到类方法名时会使用.(或::)来描述,而涉及实例方法名时,会用#来描述。
使用上下文
上下文是一个非常有用的方法,使你的测试清晰,有条理。从长远来看,这种做法使测试易于阅读。
当描述一个上下文时,请使用“when”和“with”开头。
保持描述尽可能短
一个spec描述应该从不超过40个字符。当超过时,请使用上下文进行分割。
在这个例子中,我们移除了和状态码相关的描述,用it { is_expected.to respond_with 422 }来代替。如果你通过输入“rspec filename”命令来运行测试,你将得到如下可读的输出:
单个期望测试
“仅有一个期望值”的技巧被更加广泛地表述为“每个测试应该只有一个断言”。这可以帮助你发现可能的错误,指出失败的测试,同时能让你的代码更加可读。
在孤立的单元测试中,我们通常期望每个示例仅用来展示一个行为。当一个示例中出现多个期望值时,意味着你可能正在同时声明多个行为。
无论如何,在不孤立的测试中(例如:测试中可能涉及到数据库,外部网络服务,或是一个端到端的测试),你可能会花费了很多时间重复地做同样的初始化工作,每一个测试用例中仅具有不同的期望。在这些测试中,我认为比较好的做法是声明多个单独的行为。
测试所有可能的情况
测试是一个好的习惯,但如果你不进行边界测试,测试就不会真正的有效。测试时应尽可能的测试有效的,边界以及无效的情况。例如,考虑如下的示例:
对这个例子来说,我通常看到的错误是只测试资源是否被移除。但这个动作中至少还有另外两个边界情形:当资源没有被找到,或资源不被拥有的时候。根据经验,我们应该考虑所有可能的输入并测试它们。
Expect语法vs Should 语法
对于新的工程,我们应该总是使用expect语法。
在新的工程中,我们应该配置Rspec只接受新的语法,避免使用旧的语法。
当我们想仅用一行表示期望,或者有清晰的目标时,应该使用is_expected.to。
在旧的工程上,你可以使用transpec来将旧的语法转换为新的语法。更多的关于新版的Rspec的期望相关的语法,你可以在这里找到:链接1 ,链接2
使用subject语法
如果你有若干个测试用例涉及到相同的目标时,你可以使用subject{}语法进行包装。
RSpec也可以使用一个命名的subject。
使用let和let!
当你不得不分配一个新的变量,而不是使用before来创造一个实例变量时,请使用let语句。当使用let语句时,变量仅在它第一次被使用时被加载,之后便被缓存起来直到该测试用例结束。你可在Stack Overflow中找到更好、更深入的关于let语法的解释。
请使用let语法初始化那些需要被延迟加载的行为来测试你的specs。
当你想要在block被定义时定义变量,请使用let!语法。这对填充数据库以测试查询或作用域时非常有用。可以参考下面的例子:
Mock或不 Mock
关于这个问题有很多讨论。请记得不要过度使用mock技术,尽可能测试真实行为。当你更新应用时,测试真实行为是非常有用的。
Mock技术使测试更快,但是它们通常难以使用。你需要很好的理解它们和掌握使用它们的技巧。
只创建你需要的数据
如果你曾在中等大小的项目中工作过(或小的项目),你会发现测试套件运行起来很慢。解决这个问题的重点在于不要加载超过我们需要的数据。通常我们不需要加载很多的数据。
取 factories,舍 fixtures
这是一个古老的话题,但我们仍有必要记住它。不要使用fixtures,因为他们很难控制,相反我们应尽可能地使用factories。使用它们来减少创造新数据的麻烦。
重要的一点:当我们谈到单元测试时,最好的做法是既不用fixtures也不用factories。将尽可能多的逻辑放在可以进行测试的库中,不需要使用复杂的、耗时的fixtures和factories进行的初始化工作。这篇文章可以让你了解更多。
更多关于FactoryGirl
使用matcher使测试易读
使用可读的matchers,多次检查可用的rspec matchers。
共用的测试
写测试非常好,你会因此变得越来越自信。但最终你会发现代码重复无处不在。使用下面的示例可以简化你的测试代码。
从我们的经验来看,共用的测试主要用于controller。因为不同的model相互间有很多不同的地方,通常不具有太多共同的逻辑。
测试你所看到的
深入测试你的Model和应用行为(集成测试)。不要添加无用的复杂工作来测试Controller。
当我第一次测试我的应用时,我测试了Controller,但现在我不会了。现在我只使用RSpec和Capybara来编写集成测试。为什么?因为我认为我们应该测试我们所看到的,并不需要测试Controller。你最终会发现你大部分测试都涉及到Model,并且集成测试能被轻松的整理到共用的测试来构建清晰而又可读的测试。
在Ruby社区中这是一个开放的辩论,而且两方都有力有据。支持Contorller的人们认为集成测试不能覆盖所有的测试用例,并且速度很慢。但事实上,你可以很容易地覆盖所有的用例(你为什么不这样做呢?)。你可以使用类似Guard的自动化的工具运行单个测试文件。通过这种方式,你就可以仅运行你所需要的文件来进行快速的测试,而不用打断你的工作流程。
不要使用should语句
当描述你的测试时,不要使用should语句,请使用现在时的第三人称。甚至一个比较好的开始是使用新的“expectation”语法。
请参阅should_not gem 以便在RSpec中执行此操作,并使用should_clean gem来清除以“should”开头的现有RSpec示例。
使用Guard进行自动化测试
每次更改应用程序时运行所有测试非常麻烦,这项工作会占据大量的时间并打乱你的工作进程。使用Guard,你可以自动化地运行测试,并仅运行和更新的内容相关的测试。
示例:
bundle exec guard
这里有一些Guardfile相关的示例,显示了一些基本的重载规则:
Guard是一个很好的工具,但通常它不能够满足你的所有需求。有时你的TDD工作流程最好使用快捷键,这样可以很容易地运行需要的例子。然后,在推送代码之前,您可以使用一个Rake任务来运行整个套件,vim快捷键可以从这里找到。
学习更多关于guard-rspec
更快的测试(预载Rails)
在Rails上运行测试时,需要加载整个Rails 应用。这将花费一定的时间,有可能会打断你的开发流程。为了解决这个问题,我们可以使用Zeus, Spin Spork 等解决方法。这些解决方法都会提前加载所有的不需要改变的库,重载Controllers,Models,Views,factories以及所有经常更改的文件。
你可以找到基于Spork的spec_helper和Guardfile配置。使用这个配置文件,如果一个预加载文件被改变,你就可以重新加载整个应用程序并且以很快的速度运行单个测试。
使用Spork的不足在于有时你可能会花费数小时来弄明白为什么文件没有被重新加载。如果你有一些使用Spin或者=其他的解决方案,请告诉我们。
在这里你可以找到使用Zeus的Guardfile配置。spec_helper 不需要修改。但是,在运行测试之前,您必须在控制台中运行“ zeus start”命令来启动zeus服务器。
尽管Zeus比Spork更易用,但是它的主要的缺点是相当严苛的使用要求,需要Ruby 1.9.3+(推荐使用Ruby 2.0的backported GC)以及支持FSEvents或inotify的操作系统。
有许多关于以上解决方案的批评。为了提高测试速度,我们可以只加载所需要的依赖,Zeus, Spin Spork 等库函数是解决这些问题的一个办法,但或许我们可以通过更好的设计来提供一个更好的解决方案。 了解更多相关讨论。
伪装HTTP请求
有时你需要访问外部服务。在这些场景中你可能并不能依赖于真实的服务,但是你可以使用类似webmock的方法来进行模拟。
了解更多webmock 和 VCR。了解如何将两者配合使用,请点击这里。
有用的格式化程序
使用格式化程序,可以给你有关测试套件的有用信息。我个人觉得非常好。要使其工作,请在Guardfile中添加gem并将fuubar设置为默认格式化程序。
示例1:
# Gemfile
group :development, :test do
gem 'fuubar'
示例2:
# .rspec
--drb
--format Fuubar
--color
相关书籍:
相关PPT:RSpec 2 Best practices
相关网络资源:
The Carbon Emitter Best Practices
Dmytro Shteflyuk Best Practices
thoughtbot's RSpec Related Reading
快速阅读:
Testing With RSpec Code School course
Using Zeus to speed up your tests
Code TV Screencast on Guard and Spork
Many of Destroy All Software screencasts
文档链接:
编程风格指南
我们正在寻找最佳的“易于阅读”测试的编写风格指南。目前来说 Mongoid test suite 起了一个很好的开头。它编写了简洁而又容易阅读的测试,遵照了这里所说的大部分最佳实践。
多语言 (请创建一个新的 Issue 如果你想翻译这个指南)
改善Better Specs
这是一个开源的项目。如果有什么遗漏或者错误的地方,请在 GitHub 创建一个 Issue 来讨论这个话题。同时也请查看这些已有的 Issues
这个项目的创建和发布要感谢Lelylan 项目,这是一个新的监管和控制你的设备平台,通过一个简单,开源和强壮的REST API就可以实现。
如果你想要给我捐赠,可以在这里找到我。
【英文原文】http://www.betterspecs.org/
{测试窝原创译文,译者:初心}
译者简介:初心,东南大学在读硕士研究生