ruby [rspec]“使用RSpec测试Rails程序”笔记
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了ruby [rspec]“使用RSpec测试Rails程序”笔记相关的知识,希望对你有一定的参考价值。
# model
class Contact < ActiveRecord::Base
has_many :phones
accepts_nested_attributes_for :phones
// ...
end
# controller
def contact_params
params.require(:contact).permit(:firstname, :lastname, :email,
:phones_attributes => [:id, :phone, :phone_type])
end
def create
@contact = Contact.new(contact_params)
end
# view
<%= form_for(@contact) do |f| %>
<div class="form-inputs">
<div class="field">
<%= f.label :firstname %>
<%= f.text_field :firstname %>
</div>
<div class="field">
<%= f.label :lastname %>
<%= f.text_field :lastname %>
</div>
<div class="field">
<%= f.label :email %>
<%= f.text_field :email %>
</div>
<%= f.fields_for :phones do |builder| %>
<div class="field">
<%= builder.hidden_field :phone_type %>
<%= builder.label :phone, builder.object.phone_type %>
<%= builder.text_field :phone %>
</div>
<% end %>
</div>
<div class="form-actions">
<%= f.submit nil, class: 'btn btn-primary' %>
</div>
<% end %>
# scenario 和 feature 只能用于功能测试
# feature 块不能嵌套 descibe
# feature instead describe
feature 'User management' do
// scenario instead it
scenario "adds a new user" do
admin = create(:admin)
sign_in admin
visit root_path
expect{
click_link 'Users'
click_link 'New User'
fill_in 'Email', with: 'newuser@example.com'
find('#password').fill_in 'Password', with: 'secret123'
find('#password_confirmation').fill_in 'Password confirmation',
with: 'secret123'
click_button 'Create User'
}.to change(User, :count).by(1)
// gem launcher: 可以保存当前页面并打开
save_and_open_page
expect(current_path).to eq users_path
expect(page).to have_content 'New user created'
within 'h1' do
expect(page).to have_content 'Users'
end
expect(page).to have_content 'newuser@example.com'
end
end
# 控制器动作实例化的变量可以通过 assigns(:variable_name) 方法获取
it "assigns the requested contact to @contact" do
contact = create(:contact)
get :show, id: contact
expect(assigns(:contact)).to eq contact
end
# 控制器动作的返回结果可以通过 response 获取
it "renders the :show template" do
contact = create(:contact)
get :show, id: contact
expect(response).to render_template :show
end
# attribute_for() 方法生成的是一个由属性组成的Hash,而不是对象
it "redirects to the home page upon save" do
post :create, contact: FactoryGirl.attributes_for(:contact)
expect(response).to redirect_to root_url
end
# 提供的match_array 匹配器检测数据集合(被赋值给@contacts 变量)是否和期望值
# 一致。match_array 只会检测数组的内容,而不在乎顺序。如果还要检测顺序的话,请使
# 用eq 匹配器。
it "populates an array of contacts starting with the letter" do
smith = create(:contact, lastname: 'Smith')
jones = create(:contact, lastname: 'Jones')
get :index, letter: 'S'
expect(assigns(:contacts)).to match_array([smith])
end
# be_a_new
it "assigns a new Contact to @contact" do
get :new
expect(assigns(:contact)).to be_a_new(Contact)
end
# expect a post and change or not
# 注意第一个测试用例中 expect 方法和之前不一样的用法。这里,我们把整个 HTTP
# 请求操作包含在了 expect{} 块中,这种用法比较复杂。块中的 HTTP 请求操作以 Proc 的
# 形式传入 expect 方法,这样要检测的值会在请求执行前后两次计算,能很方便的检测预想
# 的变化有没有发生。
it "saves the new contact in the database" do
expect{
post :create, contact: attributes_for(:contact,
phones_attributes: @phones)
}.to change(Contact, :count).by(1)
end
it "does not save the new contact in the database" do
expect{
post :create,
contact: attributes_for(:invalid_contact)
}.to_not change(Contact, :count)
end
# attributes_for(:contact, phones_attributes: @phones) 可以构成nested_form
before :each do
@phones = [
attributes_for(:phone),
attributes_for(:phone),
attributes_for(:phone)
]
end
post :create, contact: attributes_for(:contact, phones_attributes: @phones)
# reload
it "changes @contact's attributes" do
patch :update, id: @contact,
contact: attributes_for(:contact,
firstname: "Larry", lastname: "Smith")
@contact.reload
expect(@contact.firstname).to eq("Larry")
expect(@contact.lastname).to eq("Smith")
end
# should的用法
subject { build(:user, firstname: 'John', lastname: 'Doe') }
it { should be_named 'John Doe' }
# Shoulda 是一个匹配器扩展代码库,可以更轻松地测试常规功能。添加这样一个额外的依
# 赖库,就可以把之前要使用三行四行甚至五行的测试精简到只需一到两行。
subject{ Contact.new }
specify { should validate_presence_of :firstname }
subject { build(:user, firstname: 'John', lastname: 'Doe') }
it { should be_named 'John Doe' }
RSpec::Matchers.define :be_named do |expected|
match do |actual|
actual.name eq expected
end
description do
"return a full name as a string"
end
end
FactoryGirl.define do
factory :contact do
firstname { Faker::Name.first_name }
lastname { Faker::Name.last_name }
email { Faker::Internet.email }
after(:build) do |contact|
[:home_phone, :work_phone, :mobile_phone].each do |phone|
contact.phones << FactoryGirl.build(:phone,
phone_type: phone, contact: contact)
end
end
end
FactoryGirl.define do
factory :phone do
association :contact
phone { Faker::PhoneNumber.phone_number }
# child factories omitted ...
end
end
# 手动引入urlhelper
redirect_to Rails.application.routes.url_helpers.login_path
it "processes a credit card", focus: true do
# details of example
end
# $ bundle exec rspec . --tag focus
# 还可以设置 RSpec 只运行(或不运行)指定标签的测试用例,例如:
# spec/spec_helper.rb
Spork.prefork do
# ...
RSpec.configure do |config|
# ...
config.filter_run focus: true
end
end
# 所有属性都自动会有个带?的方法
@contact.hidden?
@contact.lastname?
@contact.created_at?
以上是关于ruby [rspec]“使用RSpec测试Rails程序”笔记的主要内容,如果未能解决你的问题,请参考以下文章