Как указано в сообщениях об ошибках, let
и subject
специально предназначены для управления состоянием для каждого примера. Но хуки before(:context)
/ before(:all)
запускаются за пределами какого-либо конкретного примера, поэтому они принципиально несовместимы. Если вы хотите использовать before(:context)
, вы не можете ссылаться на любые определения let
из ловушки. Вам придется самостоятельно управлять состоянием post_params
, не используя let
. Вот простой способ сделать это:
require 'rails_helper'
RSpec.describe V1::UsersController do
describe '#create' do
before(:context) do
@post_params = {
first_nm: Faker::Name.first_name,
last_nm: Faker::Name.last_name ,
password: "test123456",
password_confirmation: "test123456",
email_address: Faker::Internet.email
}
post :create, params: @post_params
end
context 'successful create' do
subject(:user) { User.find_by_email(@post_params[:email_address]) }
it 'persists the user' do
expect(user).not_to be_nil
end
it 'user data is correct' do
@post_params.except(:password, :password_confirmation).each do |k, v|
expect(user.send(k)).to eq(v)
end
end
it 'returns responsde code of 201' do
expect(response.status).to eq(201)
end
end
end
end
Это должно решить вашу проблему;однако это не тот подход, который я бы рекомендовал. Вместо этого я рекомендую использовать функцию aggregate_failures
в RSpec 3.3+ и поместить все это в один пример, например, так:
require 'rails_helper'
RSpec.describe V1::UsersController do
describe '#create' do
let(:post_params) do
{
first_nm: Faker::Name.first_name,
last_nm: Faker::Name.last_name ,
password: "test123456",
password_confirmation: "test123456",
email_address: Faker::Internet.email
}
end
it 'successfully creates a user with the requested params', :aggregate_failures do
post :create, params: post_params
expect(response.status).to eq(201)
user = User.find_by_email(post_params[:email_address])
expect(user).not_to be_nil
post_params.except(:password, :password_confirmation).each do |k, v|
expect(user.send(k)).to eq(v)
end
end
end
end
aggregate_failures
дает сбойотчет с указанием каждого неудавшегося ожидания (а не только первого, как обычно), точно так же, как если бы вы разделили его на 3 отдельных примера, позволяя при этом фактически сделать его одним примером. Это позволяет вам инкапсулировать тестируемое действие в одном примере, позволяя выполнять действие только один раз, как вы хотите. Во многих отношениях это лучше согласуется с изолированной программной средой состояния для каждого примера, предоставляемой функциями RSpec, такими как before
hooks, объявления let
и откат DB-транзакции, предоставляемый rspec-rails. И
Мне настолько нравится функция aggregate_failures
, что я склонен настраивать RSpec для автоматического применения ее к каждому примеру в spec_helper.rb
:
RSpec.configure do |c|
c.define_derived_metadata do |meta|
meta[:aggregate_failures] = true unless meta.key?(:aggregate_failures)
end
end