概要
RSpecを用いてJSONの検証をする際に使える rspec-json_matcher の隠された(?)能力を紹介しましょう
rspec-json_matcherとは
expect('{"a": "b", "c": "d" }').to be_json_as("a" => "b", "c" => "d")
このように、JSON文字列を直接検証できます
でも、こんな時どうする?
下記のような2つのJSONがあったとき、root の配列の順序を気にすること無く、内包している値のみに注目して検証するにはどうしたらいいでしょうか?
{
"root": [
{"a": 1},
{"b": 2}
]
}
{
"root": [
{"b": 2},
{"a": 1}
]
}
ちなみに、これでは2番目で失敗します (配列内の順番も検証してしまうため)
let(:spec) { {"root" => [{"a" => 1}, {"b" => 2}]} }
expect('{"root":[{"a":1},{"b":2}]}').to be_json_as(spec)
#=> pass
expect('{"root":[{"b":2},{"a":1}]}').to be_json_as(spec)
#=> fail
解決策
rspec-json_matcherは、RSpecのmatcherをそのまま書くことができます
今回の例では contain_exactly を使うのが良さそうです
let(:spec) { {"root" => contain_exactly({"a" => 1}, {"b" => 2})} }
expect('{"root":[{"a":1},{"b":2}]}').to be_json_as(spec)
#=> pass
expect('{"root":[{"b":2},{"a":1}]}').to be_json_as(spec)
#=> pass
またはマッチャ合成機能(and/or)とincludeを組み合わせても同じことが実現できます
let(:spec) { {"root" => include({"a" => 1}).and include({"b" => 2})} }
expect('{"root":[{"a":1},{"b":2}]}').to be_json_as(spec)
#=> pass
expect('{"root":[{"b":2},{"a":1}]}').to be_json_as(spec)
#=> pass
解説
rspec-json_matcherの例にも書いてあるとおり、値の部分には true/falseだけでなく、StringやHashといったオブジェクトタイプの他、正規表現も書くことができます
これの応用です。すなわち値に書かれた内容はそのままRSpecのmatcherとして評価されることを利用しています
これが分かっていれば、自由自在にJSON検証が可能です
注意
残念なことに、キーの方には適用(評価)できません
expect('{"root":[{"a":1},{"b":2}]}').to be_json_as( {start_with("r") => Array} )
#=> fail
#|| reason: [
#|| [0] "root",
#|| [1] "#<RSpec::Matchers::BuiltIn::StartWith:0x0055e05b3cc0d0>"
#|| ]
検証コード
RSpec 3.4.0
source "https://rubygems.org"
gem "rspec", require: "rspec/core"
gem "rspec-json_matcher", require: "rspec/json_matcher"
gem "rake"
require "bundler"
Bundler.require
RSpec.configuration.include RSpec::JsonMatcher
describe "json" do
let(:spec) {
{"root" => contain_exactly({"a" => 1}, {"b" => 2})}
}
it "order is a to b" do
expect('{"root":[{"a":1},{"b":2}]}').to be_json_as(spec)
end
it "order is b to a" do
expect('{"root":[{"b":2},{"a":1}]}').to be_json_as(spec)
end
end
実行結果
$ bundle exec rspec --format d
json
order is a to b
order is b to a
Finished in 0.00201 seconds (files took 0.09972 seconds to load)
2 examples, 0 failures
参考資料
- GitHub: r7kamura/rspec-json_matcher
- Qiita: RspecでJsonをテストするMatcher
- Qiita: 今日から使える!RSpec 3で追加された8つの新機能
あとがき
REST API開発が捗ります
ってか、APIのチェックの為だけにRSpec使っても良いくらいです (=> やってました)