RSpecのdefine_negated_matcherを使うと、カスタムマッチャーの否定形を簡単に定義できます。 not_toが使えないような複合条件のケースを作成する際に便利です。

このようなケースを想定しています。

1
2
3
4
5
6
RSpec.describe [1, 2, 3] do
  it '' do
    lists = subject.dup
    expect { lists.delete(2) }.to change { lists }.not_to include(2)
  end
end

実行すると、次のエラーが発生します。

NotImplementedError:
  `expect { }.not_to change { }.to()` is not supported

このようなケースでは次のように書けば変わらんだろうというツッコミはさておき、直接的に検証したい場合は、define_negated_matcherを使って否定形のマッチャーを定義することで解決できます。

1
expect { lists.delete(2) }.to change { lists }.to contain_exactly(1, 3)

使い方

1
2
3
4
5
6
7
8
9
RSpec::Matchers.define_negated_matcher :an_array_excluding, :include

RSpec.describe [1, 2, 3] do
  it '' do
    lists = subject.dup
    expect { lists.delete(2) }.to change { lists }.to an_array_excluding(2)
    expect { lists.delete(2) }.to change { lists }.to contain_exactly(1, 3)
  end
end

これだけでOKです。 listsは変更されて、2が含まれなくなることを検証できます。