我正在使用FactoryGirl
和Rspec
编写一些测试。
规格/工厂/ students.rb :
FactoryGirl.define do
factory :student do
end
factory :student_with_profile_and_identity, class: 'Student' do
after(:create) do |student|
create(:profile, profileable: student)
create(:student_identity, student: student)
end
end
end
规格/工厂/ profiles.rb :
FactoryGirl.define do
factory :profile do
birthday { Faker::Date.birthday(15, 150) }
sequence(:email) { |i| "profile_#{i}@email.com" }
first_name { Faker::Name.first_name }
last_name { Faker::Name.first_name }
password { Faker::Internet.password(6, 72, true, true) }
end
end
规格/工厂/ student_identities.rb :
FactoryGirl.define do
factory :student_identity do
provider { ['facebook.com', 'google.com', 'twitter.com'].sample }
uid { Faker::Number.number(10) }
end
end
规格/请求/ authorizations_spec.rb :
require 'rails_helper'
RSpec.describe 'Authorizations', type: :request do
describe 'POST /v1/authorizations/sign_in' do
let!(:student) { create(:student_with_profile_and_identity) }
context 'when the request is valid' do
subject do
post '/v1/authorizations/sign_in',
params: credentials
end
context "user signs up via social network" do
let(:credentials) do
{
authorization: {
student: {
profile_attributes: {
email: student.profile.email
},
student_identities_attributes: {
provider: student.student_identities[0].provider,
uid: student.student_identities[0].uid
}
}
}
}
end
it 'returns an authentication token' do
subject
p "1 student.profile.inspect #{student.profile.inspect}"
expect(json['token']).to(be_present)
end
end
context 'when the user has already an account' do
let(:credentials) do
{
authorization: {
email: student.profile.email,
password: student.profile.password
}
}
end
it 'returns an authentication token' do
p "2 student.profile.inspect #{student.profile.inspect}"
subject
expect(json['token']).to(be_present)
end
end
end
end
end
几乎所有测试都在通过......问题在于:
它正在每个环境中创建一个新的学生。我希望let!(:student) { ... }
类似于“singleton”,换句话说,一旦在let!(:student) { create(:student_with_profile_and_identity) }
创建/定义它,它将不再被调用。
Ex:日志是这样的:
"1 student.profile.inspect #<Profile id: 1, email: \"profile_1@email.com\", profileable_type: \"Student\", profileable_id: 1>"
"2 student.profile.inspect #<Profile id: 2, email: \"profile_2@email.com\", profileable_type: \"Student\", profileable_id: 2>"
虽然我希望实例是相同的。
我错过了什么吗?
答案 0 :(得分:0)
在RSpec中,let
and let!
是相同的,除了let
是懒惰的,而let!
是渴望的:
使用
let
定义memoized辅助方法。该值将在同一示例中的多个调用中缓存,但不会跨示例缓存。请注意,
let
是惰性求值的:直到第一次调用它定义的方法时才会对它进行求值。您可以使用let!
在每个示例之前强制调用方法。
如果您想要通过所有示例保留某些内容,可以使用before hook ... before(:context)
声音,就好像它可能是您想要的。您可以设置一个在before
块中记忆的辅助方法,以避免在任何地方使用实例变量(每this comment):
def student
@student ||= create(:student_with_profile_and_identity)
end
before(:context) do
student # force student creation
end