Rspec: everyday-rspec实操。FactoryBot预构件 (rspec-expectations gem 查看匹配器) 1-4章
RSpec.info/documentation/
包括core, expectiation,rails , mock, 点击最新版本,然后右上角搜索class, method.
第3章:
rspec-expectations gem: RSpec匹配器
第4章:
预构件gem: factory_bot
git checkout -b my-02-setup origin/01-untested
解释:从已经克隆后的远程,下载分支到本地。
Switched to a new branch 'my-02-setup'
第二章 开始
1.
Gemfile group :development, :test do
gem 'rspec-rails', '~> 3.6.0' # 省略了 Rails 提供的其他 gem
end
2. 测试数据库。
3. 配置RSpec:
$ bin/rails generate rspec:install
打开.rspec文件,增加:
作者强烈建议看spec/spec_helper.rb和spec/rails_helper.rb的设置,理解各项设置的作用。
3.1 使用 rspec binstub 提升测试组件的启动速度
group :development do
# 这一分组中的其他 gem ...
gem 'spring-commands-rspec'
end
然后 bundle exec spring binstub rspec, 如果不想用这个,直接bundle exec rspec.
然后bin/rspec试一试。
4 controller(可选)
可以使用 rspec-rails 提供的默认设置;不过这样会生成额外的样板代码,你可以自己动手删 除,也可以放着不管。
打开 config/application.rb 文件,在 Application 类中加入下面的代码:
5,附加:(Rails指南有一整章节。)
如果经常新建Rails, 可以创建一个Rails 应用模板,自动把 RSpec 和相关的配置添加到应用 的 Gemfile 和配置文件中,而且还可以自动创建测试数据库。Daniel Kehoe 开发的 Rails Composer 是个 不错的工具。
第 3 章 模型测试
git checkout -b my-03-models origin/02-setup
复制前一章分支,增加了user, project, note, task.4个models. 添加了5个gem。
1.2编写模型测试。
bin/rails g rspec:model user
模型测试应该包含:
• 使用有效属性实例化的模型应该是有效的;
• 无法通过数据验证的数据,测试应该失败;
• 类方法和实例方法应按预期可正常使用。
2.2编写模型测试
bin/rspec
首先,确定要验证的example。模型验证User
pending在之后章节学习。
2.3 RSpec句法:新:expect().to eq()
然后bin/rspec,通过验证。
2.4 测试数据验证
include匹配器检验一个可以枚举的value中是否包括指定的值。 to_not和to匹配器。
然后bin/rspec通过验证。
另外,可以修改应用代码,看看对测试有什么影响。如果测试代码的输出没有变化,可能是测试没有与代码对接上,或者代码的行为与预期不同。
关联模型的数据验证:
bin/rails g rspec:model project
这会生成models/project_spec.rb文件。也可以手动添加,但通过控制器添加文件,能防止打错字。
加2个example.
it "does not allow duplicate project names per user"
it "allows two users to share a project name"
因为在app/models/project.rb中,增加了作用域验证,这里每个project的name只有一个用户,name不是唯一的但它对应的user_id,在Project中是唯一的。
validates :name, presence: true, uniqueness: { scope: :user_id }
我们应当养成数据验证的习惯,通过和不通过都要验证。
比如:把验证代码临时注释掉,或者把测试的预期改成其他值,看看测试结果是否失败?
3.5 测试实例方法
在User model中编写一个实例方法name。可以在测试文件user_spec.rb中使用,例子:
expect(user.name).to eq("Dave Bot")
3.6测试类方法和作用域
在Note model中编写一个类方法search,它是一个作用域 :
- #A scope是狭义的data 查询。用于检索和查询类的实例对象
- #scope()是类方法:scope(name, body, &body), 等同于:
- #返回的是一个相关的记录数据集合对象,ActiveRecord::Relation,类似Array
- #箭头函数是lambda表达式,->(){return},这里成为块参数。
WHERE .. LIKE.. 模糊对比:SELECT * FROM events WHERE name LIKE '%Ruby%';
这里where()是rails语法糖。返回一个relation对象。
具体看query guide. 或者自己的博客activerecord:query
expect(Note.search("first")).to include(note1)
3.7 测试失败情况
使用be_empty匹配器,检查Note.search("something")的返回值是否为空。
空的话:expected `#<ActiveRecord::Relation []>.empty?` to return true.
3.8 匹配器
be_valid, eq, include , be_empty。 be_valid由rspec-rails gem提供。
其他的由一起安装的rspec-expectations gem提供 :https://github.com/rspec/rspec-expectations
第8章 ,自定义匹配器
3.9 refactor重构: describe, context, before, after.
describe 用来表示 需要实现的功能
context 针对该功能不同的情况
it : 返回什么结果。 使用动词说明希望得到的结果。
before: 设定测试数据。消除重复。这是简写,全的是before(:each),在块内的每个example之前运行一次,有几个example就运行几次。
before(:all):在块内的all examples之前运行一次,之后不再运行。
before(:suit):) 在整个测试组件之前运行。
after: 假如测试在用例执行后需要做些清理工作,例如中断与外部服务的连接, after 块也有 each、all 和 suite 三个选项。因为 RSpec 会自行清理数据库,所以我很 少使用 after。
3.10小结:
- 明确指定希望得到的结果:使用动词说明希望得到的结果。每个测试用例只测试一种情况。
- 测试希望看到的结果和不希望看到的结果
- 测试极端情况
- • 测试要良好地组织,保证可读性:使用 describe 和 context 组织测试,形成一个清晰的大纲;使用 before 和 after 块消除代码重复。
第 4 章 创建有意义的测试数据
用预构件代替固件fixture
4.1安装
Gemfile
group :development, :test do
gem "rspec-rails", "~> 3.6.0"
gem "factory_bot_rails" # 改名了,以前叫factory_girl
end
config/application.rb 把fixture: false去掉了。
4.2 开始用
bin/rails generate factory_bot:model usercreate spec/factories/users.rbFactoryBot.define dofactory :user do first_name "Aaron" last_name "Sumner" email "tester@example.com" password "dottle-nouveau-pavilion-tights-furze" end # 现在,在测试中可以调用 FactoryBot.create(:user) end
spec/models/user_spec.rb
require 'rails_helper'
describe User do
it "has a valid factory" do
expect(FactoryBot.build(:user)).to be_valid
end
## 其他测试用例 ...
end
记住:FactoryBot.build 的作用是在内存中创建一个新测试对象;
FactoryBot.create 的作用
是把对象持久存储到应用的测试数据库中。
4.3 使用序列生成唯一的数据
it "does something with multiple users" do
user1 = FactoryGirl.create(:user)
user2 = FactoryGirl.create(:user)
expect(true).to be_true
end
希望user1,和user2,都可以创建出来,对于唯一属性,可以使用secquence方法来设置,每创建一个对象,唯一属性自动加1.
sequence(:email) { |n| "tester#{n}@example.com" }
4.4 Factory中的 Association
FactoryBod比纯粹的fixtures功能强大的多,可以处理models之间的Association.
bin/rails generate factory_bot:model note
bin/rails g factory_bot:model project
FactoryBot.define do
factory :project d
sequenct(:name) {|n| "Project #{n}"} #因为为name设置 uniqueness: {scope: :user_id}
description "A test project"
due_on 1.week.from_now
association :owner #关联到user,因为在模型project.rb中设置了别名
end
end
在用户预构件factories/users.rb中,在第二行,就是为预构件起名的那一行,加上别名
owner。 原因见后面2段文字。
factory :user, aliases:[:owner] do
因为预构件已经定义:user, :project 和:note,并建立了Association。所以在:
models/note_spec.rb中,只创建了note记录用,同时note.project就创建了project记录并关联上了。
inspect()方法检查是否关联。
inspect方法 返回所关联的对象。
不过注意⚠️ 预构件可能会骗人,因为它会先创建一个关联的用户(项目的属主),再创建一个用户(记录的属主),因此note.user.inspect返回的对象的email属性将是test2@example.com, 而不是预想的text1@example.com
为了避免这种问题,我们可以修改记录预构件,把两个用户统一:
回头看一下app/models/project.rb:Project模型关联的user的别名叫"owner"
belongs_to :owner, class_name: User, foreign_key: :user_id
这就是前面在users.rb加上aliases:[:owner]代码的原因: 让F a c to r y B o t知道可以通过别名"owner"引用预构件user.
4.6 避免预构件中出现重复
同种类型的数据可以定义多个预构件。例如,为了测试项目是按期完成的还是延期了,可以为预构件设定不同的名称,指定不同的属性 .
⚠️需要
Rspec: everyday-rspec实操。FactoryBot预构件 (rspec-expectations gem 查看匹配器) 1-4章的更多相关文章
- Rspec: everyday-rspec实操。5:controller test(了解基础)
第 5 章 控制器测试 5.1基础 rails generate rspec:controller home RSpec.describe HomeController, type: :control ...
- Rspec: everyday-rspec实操: 第8章DRY. (6个方法,其中3个方法好上手)
Don't Repeat Yourself. • 把操作步骤提取到辅助模块中;✅ • 通过let复用测试中的实例变量;✅ • 把通用的设置移到共享的情景中;⚠️(不喜欢) • 在RSpec和rspec ...
- Rspec: everyday-rspec实操: 第9章 快速编写测试,编写快速的测试。
Make it work, make it right, make it fast. 测试运行的时间.应用和测试组件的增长,速度会越来越慢,目标是保持代码的readable, maintainable ...
- 百度NLP预训练模型ERNIE2.0最强实操课程来袭!【附教程】
2019年3月,百度正式发布NLP模型ERNIE,其在中文任务中全面超越BERT一度引发业界广泛关注和探讨.经过短短几个月时间,百度ERNIE再升级,发布持续学习的语义理解框架ERNIE 2.0,及基 ...
- .net基础学java系列(四)Console实操
上一篇文章 .net基础学java系列(三)徘徊反思 本章节没啥营养,请绕路! 看视频,不实操,对于上了年龄的人来说,是记不住的!我已经看了几遍IDEA的教学视频: https://edu.51cto ...
- 动手实操(一):如何用七牛云 API 实现相片地图?
实操玩家: 在苹果手机上,我们只要打开定位服务,拍照后便能在相簿中找到地图,地图上显示着在各地拍摄的相片.网站上这种显示方式也并不少见,例如 Flickr.即将关闭的 Panoramio 等. 作为地 ...
- 决策树算法的Python实现—基于金融场景实操
决策树是最经常使用的数据挖掘算法,本次分享jacky带你深入浅出,走进决策树的世界 基本概念 决策树(Decision Tree) 它通过对训练样本的学习,并建立分类规则,然后依据分类规则,对新样本数 ...
- Istio的流量管理(实操三)
Istio的流量管理(实操三) 涵盖官方文档Traffic Management章节中的egress部分.其中有一小部分问题(已在下文标注)待官方解决. 目录 Istio的流量管理(实操三) 访问外部 ...
- 72 个网络应用安全实操要点,全方位保护 Web 应用的安全
原文地址:Web Application Security Checklist 原文作者:Teo Selenius(已授权) 译者 & 校正:HelloGitHub-小熊熊 & 卤蛋 ...
随机推荐
- 20154312 曾林 Exp4恶意软件分析
写在前面 如果把恶意软件比作罪犯的话,怎么看这次实验? 实验目的:以后能够在茫茫人海中找到罪犯. 实验过程:现在以及抓到了一个罪犯,把他放到茫茫人海里去,看看他和普通人有啥区别.这些区别就是罪犯的特征 ...
- M2C的概念
M2C即Manufacturers to Consumer(生产厂家对消费者),生产厂家(Manufacturers)直接对消费者(Consumers)提供自己生产的产品或服务的一种商业模式,特点是流 ...
- Python的问题解决: IOError: [Errno 32] Broken pipe
被该问题困扰的人还是挺多的,所以又对这个问题进行了一些更深入的分析,希望可以解决读者的问题新版本:Python 的 Broken Pipe 错误问题分析 遇到一个很奇怪的问题, web.py代码里面报 ...
- 论文笔记之《Event Extraction via Dynamic Multi-Pooling Convolutional Neural Network》
1. 文章内容概述 本人精读了事件抽取领域的经典论文<Event Extraction via Dynamic Multi-Pooling Convolutional Neural Networ ...
- MySQL用sql复制表数据到新表的方法
用sqlyog无法直接复制出一个不同表名的表来,只能copy到其他库上同名的表. 在MySQL数据库中,应该如何用sql将表数据复制到新表中呢? 本人通过试验测试成功了,而且相当简单易懂,速度也非常快 ...
- Python Web学习笔记之TCP/IP协议原理与介绍
HTTP.FTP.SMTP.Telnet等等协议,哦!那个HTTP协议啊就是访问网页用的那个协议啊然后那个······其实······你懂得,我们应该从实际来了解他,理解网络协议的作用与功能,然后再从 ...
- php json_decode返回null
在使用json_decode函数想把json串转化为数组的时候,出现了null,当时还以为是因为json对字符串的长度有限制,还以为是因为两边少了引号,经过多次处理,发现都没有效果. 百度各种帖子,发 ...
- c++编程和c在思想上最大的差别
从正规的血统上来说,c++跟java一样是面向对象编程语言,而c是面向结构的编程语言.但是,在现实中,有大量的系统虽然用cpp编写,但是100%跟java一样,使用面向对象的几乎没有,绝大部分都是结合 ...
- Educational Codeforces Round 21 Problem A - C
Problem A Lucky Year 题目传送门[here] 题目大意是说,只有一个数字非零的数是幸运的,给出一个数,求下一个幸运的数是多少. 这个幸运的数不是最高位的数字都是零,于是只跟最高位有 ...
- Android和PHP开发最佳实践
Android和PHP开发最佳实践 <Android和PHP开发最佳实践>基本信息作者: 黄隽实丛书名: 移动应用开发技术丛书出版社:机械工业出版社ISBN:9787111410508上架 ...