【发布时间】:2019-09-17 14:35:46
【问题描述】:
我已经开始使用 Rspec 并且现在我编写了几个成功且非常困难的测试。但由于我需要更多练习,所以我对这些测试做了几次重构。
我在 Rspec 的文档中没有找到我的问题的答案,这就是我在这里的原因。
问题是关于指令let,它提供了通过第一次调用返回一些对象的能力,而不仅仅是,你知道的。
我当前的 rspec 代码部分是:
RSpec.describe 'Users', type: :request do
describe 'profiles' do
context 'should be visible by' do
it 'related company managers' do
company = create(:company)
sign_in create(:manager, :company, company: company) # Pay attention on this
get user_path(create(:member, :company, company: company)) # this
expect(response).to have_http_status 200
end
it 'related company owners' do
company = create(:company)
sign_in create(:owner, :company, company: company) # this
get user_path(create(:member, :company, company: company)) # and this
expect(response).to have_http_status 200
end
end
end
end
在用户规范下只有两个 63 示例,但它们已经足够了。我想重构代码以使用let,它将定义一个带参数的方法,如下所示:
RSpec.describe 'Users', type: :request do
let(:member) do |entity_name = :company, entity = create(entity_name)|
create :member, entity_name, entity_name => entity
end
let(:manager) do |entity_name = :company, entity = create(entity_name)|
create :manager, entity_name, entity_name => entity
end
let(:owner) do |entity_name = :company, entity = create(entity_name)|
create :owner, entity_name, entity_name => entity
end
describe 'profiles' do
context 'should be visible by' do
it 'related company managers' do
company = create(:company)
sign_in manager(:company, company) # Become more readable here
get user_path(member(:company, company)) # here
expect(response).to have_http_status 200
end
it 'related company owners' do
company = create(:company)
sign_in owner(:company, company) # here
get user_path(member(:company, company)) # and here.
expect(response).to have_http_status 200
end
end
end
end
在重构之后,Guard 说:
1) Users profiles should be visible by related company managers
Failure/Error: sign_in manager(:company, company) # Become more readable here
ArgumentError:
wrong number of arguments (given 2, expected 0)
# ./spec/requests/users_spec.rb:38:in `block (4 levels) in <top (required)>'
从我看到的Rspec核心的memorized_helpers.rb:
def let(name, &block)
# We have to pass the block directly to `define_method` to
# allow it to use method constructs like `super` and `return`.
raise "#let or #subject called without a block" if block.nil?
raise(
"#let or #subject called with a reserved name #initialize"
) if :initialize == name
MemoizedHelpers.module_for(self).__send__(:define_method, name, &block)
# Apply the memoization. The method has been defined in an ancestor
# module so we can use `super` here to get the value.
if block.arity == 1
define_method(name) { __memoized.fetch_or_store(name) { super(RSpec.current_example, &nil) } }
else
define_method(name) { __memoized.fetch_or_store(name) { super(&nil) } }
end
end
看起来let 的块应该用参数定义。或不?
我没有足够的经验来确定它,我很乐意找到它。
【问题讨论】:
标签: ruby-on-rails rspec ruby-on-rails-5 rspec3