RSpec:期望改变多个
RSpec: Expect to change multiple
我想在功能规范中提交表单时检查模型中的许多更改。例如,我想确保用户名从 X 更改为 Y,并且加密密码被更改为任意值。
我知道已经有一些问题,但我没有找到适合我的答案。最准确的答案似乎是 Michael Johnston 的 ChangeMultiple
匹配器:Is it possible for RSpec to expect change in two tables?。它的缺点是只能检查从已知值到已知值的显式变化。
我创建了一些关于我认为更好的匹配器的伪代码:
expect {
click_button 'Save'
}.to change_multiple { @user.reload }.with_expectations(
name: {from: 'donald', to: 'gustav'},
updated_at: {by: 4},
great_field: {by_at_leaset: 23},
encrypted_password: true, # Must change
created_at: false, # Must not change
some_other_field: nil # Doesn't matter, but want to denote here that this field exists
)
我还创建了 ChangeMultiple
匹配器的基本框架,如下所示:
module RSpec
module Matchers
def change_multiple(receiver=nil, message=nil, &block)
BuiltIn::ChangeMultiple.new(receiver, message, &block)
end
module BuiltIn
class ChangeMultiple < Change
def with_expectations(expectations)
# What to do here? How do I add the expectations passed as argument?
end
end
end
end
end
但现在我已经收到这个错误:
Failure/Error: expect {
You must pass an argument rather than a block to use the provided matcher (nil), or the matcher must implement `supports_block_expectations?`.
# ./spec/features/user/registration/edit_spec.rb:20:in `block (2 levels) in <top (required)>'
# /Users/josh/.rvm/gems/ruby-2.1.0@base/gems/activesupport-4.2.0/lib/active_support/dependencies.rb:268:in `load'
# /Users/josh/.rvm/gems/ruby-2.1.0@base/gems/activesupport-4.2.0/lib/active_support/dependencies.rb:268:in `block in load'
非常感谢在创建此自定义匹配器方面提供的任何帮助。
在RSpec 3 中,您可以一次设置多个条件(因此不会破坏单一期望规则)。它看起来像:
expect {
click_button 'Save'
@user.reload
}.to change { @user.name }.from('donald').to('gustav')
.and change { @user.updated_at }.by(4)
.and change { @user.great_field }.by_at_least(23}
.and change { @user.encrypted_password }
虽然这不是一个完整的解决方案 - 就我的研究而言,还没有简单的方法可以做到 and_not
。我也不确定你最后一次检查(如果没关系,为什么要测试它?)。当然,您应该能够将其包装在 custom matcher.
中
如果您想测试多条记录未被更改,您可以使用 RSpec::Matchers.define_negated_matcher
反转匹配器。所以,添加
RSpec::Matchers.define_negated_matcher :not_change, :change
到文件顶部(或 rails_helper.rb
),然后您可以使用 and
:
链接
expect{described_class.reorder}.to not_change{ruleset.reload.position}.
and not_change{simple_ruleset.reload.position}
已接受的答案并非 100% 正确,因为 RSpec 版本中添加了对 change {}
的 完整 复合匹配器支持3.1.0。如果您尝试 运行 使用 RSpec 3.0 版接受的答案中给出的代码,您会收到错误消息。
为了在 change {}
中使用复合匹配器,有两种方法;
- 第一个是,你必须至少有 RSpec 版本 3.1.0.
- 第二个是,您必须将
def supports_block_expectations?; true; end
添加到 RSpec::Matchers::BuiltIn::Compound
class 中,可以通过猴子修补它或直接编辑 gem 的本地副本。 重要说明:这种方式并不完全等同于第一种方式,expect {}
块运行s多次这样!
可以找到添加了对复合匹配器功能的完全支持的拉取请求 here。
是最好的,但是如果你使用的是 RSpec 2(或者有更复杂的匹配器,比如 .should_not
),这个方法也有效:
lambda {
lambda {
lambda {
lambda {
click_button 'Save'
@user.reload
}.should change {@user.name}.from('donald').to('gustav')
}.should change {@user.updated_at}.by(4)
}.should change {@user.great_field}.by_at_least(23)
}.should change {@user.encrypted_password}
我想在功能规范中提交表单时检查模型中的许多更改。例如,我想确保用户名从 X 更改为 Y,并且加密密码被更改为任意值。
我知道已经有一些问题,但我没有找到适合我的答案。最准确的答案似乎是 Michael Johnston 的 ChangeMultiple
匹配器:Is it possible for RSpec to expect change in two tables?。它的缺点是只能检查从已知值到已知值的显式变化。
我创建了一些关于我认为更好的匹配器的伪代码:
expect {
click_button 'Save'
}.to change_multiple { @user.reload }.with_expectations(
name: {from: 'donald', to: 'gustav'},
updated_at: {by: 4},
great_field: {by_at_leaset: 23},
encrypted_password: true, # Must change
created_at: false, # Must not change
some_other_field: nil # Doesn't matter, but want to denote here that this field exists
)
我还创建了 ChangeMultiple
匹配器的基本框架,如下所示:
module RSpec
module Matchers
def change_multiple(receiver=nil, message=nil, &block)
BuiltIn::ChangeMultiple.new(receiver, message, &block)
end
module BuiltIn
class ChangeMultiple < Change
def with_expectations(expectations)
# What to do here? How do I add the expectations passed as argument?
end
end
end
end
end
但现在我已经收到这个错误:
Failure/Error: expect {
You must pass an argument rather than a block to use the provided matcher (nil), or the matcher must implement `supports_block_expectations?`.
# ./spec/features/user/registration/edit_spec.rb:20:in `block (2 levels) in <top (required)>'
# /Users/josh/.rvm/gems/ruby-2.1.0@base/gems/activesupport-4.2.0/lib/active_support/dependencies.rb:268:in `load'
# /Users/josh/.rvm/gems/ruby-2.1.0@base/gems/activesupport-4.2.0/lib/active_support/dependencies.rb:268:in `block in load'
非常感谢在创建此自定义匹配器方面提供的任何帮助。
在RSpec 3 中,您可以一次设置多个条件(因此不会破坏单一期望规则)。它看起来像:
expect {
click_button 'Save'
@user.reload
}.to change { @user.name }.from('donald').to('gustav')
.and change { @user.updated_at }.by(4)
.and change { @user.great_field }.by_at_least(23}
.and change { @user.encrypted_password }
虽然这不是一个完整的解决方案 - 就我的研究而言,还没有简单的方法可以做到 and_not
。我也不确定你最后一次检查(如果没关系,为什么要测试它?)。当然,您应该能够将其包装在 custom matcher.
如果您想测试多条记录未被更改,您可以使用 RSpec::Matchers.define_negated_matcher
反转匹配器。所以,添加
RSpec::Matchers.define_negated_matcher :not_change, :change
到文件顶部(或 rails_helper.rb
),然后您可以使用 and
:
expect{described_class.reorder}.to not_change{ruleset.reload.position}.
and not_change{simple_ruleset.reload.position}
已接受的答案并非 100% 正确,因为 RSpec 版本中添加了对 change {}
的 完整 复合匹配器支持3.1.0。如果您尝试 运行 使用 RSpec 3.0 版接受的答案中给出的代码,您会收到错误消息。
为了在 change {}
中使用复合匹配器,有两种方法;
- 第一个是,你必须至少有 RSpec 版本 3.1.0.
- 第二个是,您必须将
def supports_block_expectations?; true; end
添加到RSpec::Matchers::BuiltIn::Compound
class 中,可以通过猴子修补它或直接编辑 gem 的本地副本。 重要说明:这种方式并不完全等同于第一种方式,expect {}
块运行s多次这样!
可以找到添加了对复合匹配器功能的完全支持的拉取请求 here。
.should_not
),这个方法也有效:
lambda {
lambda {
lambda {
lambda {
click_button 'Save'
@user.reload
}.should change {@user.name}.from('donald').to('gustav')
}.should change {@user.updated_at}.by(4)
}.should change {@user.great_field}.by_at_least(23)
}.should change {@user.encrypted_password}