老习惯,列出本文参考的文档和博客,致以崇高的敬意
1.FactoryGirl: http://www.jianshu.com/p/dfd0ca700a36
2.rspec 入门教程: http://www.jianshu.com/p/1db9ee327357
3.faker介绍:https://github.com/stympy/faker
简介
上文讲到要引入factory_girl
和 faker
来进行自动化测试,下面对它们进行简要介绍:
(1) factory_girl:
factory的wiki解释是: factory method pattern is a creational pattern that uses factory methods to deal with the problem of creating objects without having to specify the exact class of the object that will be created.
简而言之:一个用来创建对象数据的工具,而且它不需要我们关注细节;
factory_girl是专门用来构造模拟数据的,完美替代Fixture的工具,Fixture的缺点很明显,经常要处理各种关联和依赖。如果测试要求的数据量大,还要自己手动制造数据。 这些在Factory Girl中都有了好的解决。生成大量数据可以用association来解决对象间的关联,sequence来解决生成大量测试数据的问题
(2) faker:
用来创建比较真实的假数据,下面是真实的实例。
Faker::Name.name #=> "Christophe Bartell"
Faker::Internet.email #=> "kirsten.greenholt@isher.info"
Faker::Geolocation.lat #=> 38.4685363769531
Faker::Geolocation.lng #=> -87.888795
Faker::Address.street_address #=> "95519 Evans Oval"
Faker::Lorem.sentence #=> "Aut recusandae quam cum omnis aut dolores."
Faker::Lorem.paragraph #=> "Earum et est qui id totam adipisci sint.
Step 1: 创建应用,进行配置
话不多讲,还是新建一个rails应用来开始今天的旅途:
rails new demo160810
修改Gemfile文件的配置信息,将所需的gem包添加进去
group :development, :test do
gem 'rspec-rails','3.5.1'
gem 'factory_girl_rails','4.7.0'
gem 'faker','1.6.6'
end
执行bundle install来安装使用的gem.
bundle install
初始化rspec, 生成rspec相关文件夹和配置文件
rails generate rspec:install
生成的文件信息如下:
使用脚手架生成相关内容(我们习惯性的还是创建一个Girl,作为我们的例子):
rails g scaffold Girl
创建的文件信息如下:
直观信息见下图,可以看到, 在spec/目录下生成controllers,models、views、 request、factories等相应的文件夹和文件, 我们可以在里面编写相应的测试。
Step 2:创建模型方法
修改app/models/girl.rb文件
class Girl < ApplicationRecord
attr_accessor :name, :phone_number, :address, :single, :beautiful, :age
def have_chance?
return self.single
end
# 符合胃口的条件: (25岁以下,单身即可)||(25岁以上,单身且漂亮)
def your_taste?
return (self.age <= 25 && self.single) || (self.age > 25 && self.beautiful && self.single)
end
# 给你一个数组,里面包含多个girl, 筛选出符合你胃口 的 girl
# 要求封装一个response[Hash],作为该方法的返回值
def self.choose_some_from_many(girls = [])
response = {
code: false, # 存在的话 true, 不存在的话(result内部为空) false
result: {} # 存储 id=>girl id从0开始递增
}
id = 0
girls.each do |girl|
if girl.your_taste?
response[:result][id] = girl
id = id + 1
end
end
if response[:result].size() > 0
response[:code] = true
end
return response
end
end
较比之前有三处改动:
1、模型Girl的属性增加到6个(姓名,手机号,地址,是否单身,是否漂亮,年龄)
2、改了符合胃口的条件:(25岁以下,单身即可)||(25岁以上,单身且漂亮)
3、为广大男同胞提供了一个选择女孩的方法(choose_some_from_many),可以从海量女孩里面选出符合自己胃口的女孩,(这是个类方法,直接使用[类名.methodName]调用,实例对象无法调用)。
回顾下 通过手动创建对象数据的方法 进行测试的过程
目的:我们要测试 这个模型方法Girl.choose_some_from_many
返回的信息是否正确。
所以我们最好构建出:能够尽可能涵盖 你模型方法中 的逻辑判断条件 所有状态的数据(众所周知,逻辑判断条件如果越复杂,排列组合的状态总数就会很大),手工提供这么多组case,会很麻烦;
既然是回顾,我手工创建了三个girl对象数据,用来测试
spec/models/girl_spec.rb
require 'rails_helper'
RSpec.describe Girl, :type => :model do
before(:all){
params_1 = {
name: "rose", phone_number: "13245454545", address: "zhangheng road",
single: true, beautiful: true, age: 22
}
params_2 = {
name: "hanmeime", phone_number: "13212345678", address: "zhangheng road",
single: false, beautiful: true, age: 24
}
params_3 = {
name: "lili", phone_number: "18911547847", address: "zhangheng road",
single: true, beautiful: true, age: 30
}
@girl_1 = Girl.new(params_1)
@girl_2 = Girl.new(params_2)
@girl_3 = Girl.new(params_3)
}
# 数据: 3个女孩的信息, 测试choose_some_from_many方法的 返回结果是否正确
it "test choose_some_from_many( three girls)" do
response = Girl.choose_some_from_many(girls = [@girl_1, @girl_2, @girl_3])
p response
if response[:code] == false
expect(response[:result]).blank?
elsif response[:code] == true
response[:result].each do |k, v|
expect(v.your_taste?).to eq(true)
end
end
end
end
在测试用例中,我们对模型方法Girl.choose_some_from_many
返回的response进行验证,看其是否满足我们的需求,如果code为fasle,则result应该为空,如果code为true,则result里保存的众多girl,应该要满足我们之前定义的筛选条件。
执行测试命令:
rspec spec/models/girl_spec.rb
得到如下结果:
仍然,用一个极富深意的点,告诉我们该测试用例通过了。
问题来了:如果要创建几十个,几百个女孩,并且要求数据尽量真实,那从哪里去搞这么多数据? 这时候手动创建测试数据,就无法满足我们的需求了。于是 factory_girl 和 faker就要出场了。
Step 3: 使用factory_girl 和 faker
3.1 Factory生成文件存放的位置
通过Factory Girl生成器生成的文件都会放在 spec/factories文件夹中,文件的名字会是用对应模型名字的复数形式(所以Girl模型的预构件文件是spec/factories/grils.rb)
3.2 spec/spec_helper.rb文件中配置如下
以前使用 create(xxx),create_list(xxx),build_stubbed(XXX),attributes_for(xxx)等
方法时候, 都必须使用FactoryGirl.create(xxx) FactoryGirl.create_list(xxx)...格式; 从Factory Girl 3.0 开始, 只要做一个设置,Rails就会变得简洁, 可以加在rails_helper.rb文件Rspec.configure块中的任何地方。
RSpec.configure do |config|
config.include FactoryGirl::Syntax::Methods
end
然后在测试的代码中,就能使用比较简洁的语法;
可以直接使用create(xxx),create_list(xxx),build_stubbed(XXX),attributes_for(xxx)等方法(新手的话,还是建议在这些方法前加上 FactoryGirl. 个人感觉更加直观,知道这些方法来自哪里,熟练以后,再去掉也不迟)
3.3 正式开始
factory_girl 的create_list(xxx), build_list(xxx).可以创建一组对象数据
faker 可以动态生成一些类似真实数据的 假数据。
首先,我们先看看spec/factories/girls.rb
长什么样子:
在factory:girl do ...end 块中,我们可以把生成对象的零件放进去,这样就能够创建出来对象来了。
修改 spec/factories/girls.rb 文件
FactoryGirl.define do
factory :girl do
# 方式1: 指定 (固定)
# name "jack"
# phone_number "13945756489"
# address "zhangheng Road 666"
# single true
# beautiful false
# age 24
# 方式2: 使用faker,制作类似真实数据的 假数据 (不固定,产生不同的数据)
name {Faker::Name.name }
phone_number { Faker::PhoneNumber.cell_phone }
address { Faker::Address.street_address }
single { Faker::Boolean.boolean }
beautiful { Faker::Boolean.boolean }
age {Faker::Number.between(20,30) }
end
end
方式1:可以固定每个零件的信息(那么制造出来的 对象,就都一模一样了)
方式2:使用faker,动态配置每个零件的信息(那么制造出来的对象,基本会有所不同[相同的概率很低,但>0])
然后修改spec/models/girl_spec.rb 文件:
require 'rails_helper'
RSpec.describe Girl, :type => :model do
before(:all){
@girl_1 = FactoryGirl.create(:girl)
@girls = FactoryGirl.create_list(:girl, 20)
}
# 数据: 1个女孩的信息, 测试choose_some_from_many方法的 返回结果是否正确
it "test 1 girl" do
response = Girl.choose_some_from_many(girls = [@girl_1])
# p response
if response[:code] == false
expect(response[:result]).blank?
elsif response[:code] == true
response[:result].each do |k, v|
expect(v.your_taste?).to eq(true)
end
end
end
# 数据: 多个女孩的信息, 测试choose_some_from_many方法的 返回结果是否正确
it "test ,many girls" do
response = Girl.choose_some_from_many(girls = @girls)
# p response
if response[:code] == false
expect(response[:result]).blank?
elsif response[:code] == true
response[:result].each do |k, v|
expect(v.your_taste?).to eq(true)
end
end
end
end
在before语句块内,我们通过factory_girl的 create方法 创建了1个girl对象数据;
通过factory_girl的 create_list方法,创建了多个girl对象数据,得到的是一个包含多个girl对象的数组。
分别用两个测试用例中分别运用这两个构建的数据,来测试方法的正确性:
运行测试命令:
rspec spec/models/girl_spec.rb
运行结果如下图:“..”表示两个测试用例均通过
另外让我们看一下factory创建出的2组数据(create方法创建出的1个girl对象,create_list方法创建出的多个(20)girl对象数组),在控制台输出,看一下:
create方法创建出的1个girl对象(通过了筛选):
Maxwell Wolff,993.452.1229,589 Barton Canyon,true,true,30
create_list方法创建出的多个(20)girl对象数组, 筛选出来的有8个。
Aglae Quitzon,(476) 919-8629,78258 Angeline Fort,true,false,23
Linnie Lebsack,(330) 092-5259,5825 Mortimer Drive,true,true,21
Megane Barton Sr.,534.363.9597,7709 Rolfson Groves,true,false,20
Miss Deangelo Bins,(173) 607-1957,9732 Maya Flats,true,false,21
Bernard Kiehn,700.037.5700,627 Cecile Island,true,true,23
Ms. Stan Kertzmann,1-528-834-5310,7121 Jaron Mountain,true,false,22
Alva Borer,1-851-850-2001,59440 Duncan Trafficway,true,false,20
Jared Treutel Sr.,359-901-8795,882 Rosalind Square,true,false,24
暂时介绍到这,后续有新的东西再补充。