使用 RSpec 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
before do
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

我只希望这个控制器被击中一次。但是,我似乎无法使其起作用。

我尝试设置before(:context)但出现错误

RuntimeError:
let declaration `post_params` accessed in a `before(:context)` hook at:
`let` and `subject` declarations are not intended to be called
in a `before(:context)` hook, as they exist to define state that
is reset between each example, while `before(:context)` exists to
define state that is shared across examples in an example group.

我不希望为如此简单的测试保留多个用户。我也不想为每个示例都点击 api。

我希望before块运行一次。我该怎么做?

如错误消息所述,letsubject专门用于管理每个示例的状态。 但是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

这应该可以解决你的问题;但这不是我推荐的方法。 相反,我建议您使用 RSpec 3.3+ 的aggregate_failures功能,并将所有这些放在一个示例中,如下所示:

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钩子,let声明和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

您要查找的是before(:all),它将在所有情况之前运行一次。 也有类似的after(:all)

有趣的是,before基本上是一种较短的before(:each)说法(IMO更有意义(。

相关内容

  • 没有找到相关文章

最新更新