预计 rspec 中的多个 not_to 改变预期

Expect multiple not_to change expectations in rspec

我正在尝试通过一个操作确保某些数据保持不变:

expect {
  # running migration and user reload here
}.not_to change(user, :avatar_url).from(sample_avatar_url).and change(user, :old_avatar).from(nil)

sample_avatar_url 是在规范文件开头定义的字符串。

基本上,我想检查 avatar_urlold_avatar 是否未受到 expect 块中发生的事情的影响。

以上代码的输出是:

expect(...).not_to matcher.and matcher is not supported, since it creates a bit of an ambiguity. Instead, define negated versions of whatever matchers you wish to negate with RSpec::Matchers.define_negated_matcher and use expect(...).to matcher.and matcher.

这行不通,因为不清楚这意味着不更改第一个而不更改第二个,还是不更改第一个但更改第二个。你有几个选择来解决这个问题

因为您正在检查静态值,所以不要使用更改

..run migration and user reload..
expect(user.avatar_url).to eq(sample_avatar_url)
expect(user.old_avatar).to eq nil

或使用define_negated_matcher创建一个not_change匹配器

RSpec::Matchers.define_negated_matcher :not_change, :change
expect {
  # running migration and user reload here
}.to not_change(user, :avatar_url).from(sample_avatar_url).and not_change(user, :old_avatar).from(nil)

正如 Thomas 回答中所述,它不起作用,因为它的读数不清晰,您可以创建一个否定的匹配器。另一种选择是使用 saharspec gem and its dont 匹配器否定。

这是项目自述文件的摘录:

Another (experimental) attempt to get rid of define_negated_matcher. dont is not 100% grammatically correct, yet short and readable enought. It just negates attached matcher.

# before
RSpec.define_negated_matcher :not_change, :change

it { expect { code }.to do_stuff.and not_change(obj, :attr) }

# after: no `define_negated_matcher` needed
require 'saharspec/matchers/dont'

it { expect { code }.to do_stuff.and dont.change(obj, :attr) }

所以你可以写下你的期望而不用像这样创建一个否定的匹配器:

expect {
  # running migration and user reload here
}.to dont.change(user, :avatar_url).from(sample_avatar_url).and 
    dont.change(user, :old_avatar).from(nil)