ResponseCodeMatchers.gem
https://github.com/r7kamura/response_code_matchers
夕方ぐらいにControllerのspecを書いていて「subject.code.should == "422"...」みたいなコードを書いていて、急に思い立って初めてCustom MatcherをつくってGemにした。
使い方
spec_helper.rbでこういう感じで設定すると使えるようになる。
# spec/spec\_helper.rb require "response\_code\_matchers" RSpec.configure do |config| config.include ResponseCodeMatchers end
今まではresponse.code.should == "422"って書いてたのを、こういう風に書けるようになる。Railsのcontrollerのspecだと、postやgetがresponseオブジェクトを返す。自分は大体subjectでpostやgetを呼ぶことが多いので、そういうときに良い感じに書ける。
# spec/controllers/blogs\_controller.rb describe BlogsController do describe "#create" do subject do post :create, params end let(:params) do { :title =\> "title", :body =\> "body", :token =\> "token", :user\_id =\> 1 } end # 201 context "with valid token" do it { should be\_created } end # 400 context "without user\_id" do before do params.delete(:user\_id) end it { should be\_bad\_request } end # 401 context "with invalid token" do before do params[:token] = "invalid" end it { should be\_unauthorized } end end end
実装
RackがHTTPステータスコードと名前の対応表を持っているので、それを利用してMatcherをつくる。
https://github.com/rack/rack/blob/master/lib/rack/utils.rb#L548
CustomMatcherは2通りの作り方がある。
1つはRSpec::Matchers.defineで簡単につくる方法。
1つはMatcher用のmodule + classを用意してあげる方法。
RSpec::Matchers.define :be\_a\_multiple\_of do |expected| match do |actual| actual % expected == 0 end end
Matchersモジュールは、Matcherクラスのインスタンスを返すようなmatcherメソッドを定義すれば良い。
Matcherクラスは、以下のメソッドを持っていれば良い。
- #matches?
- #description
- #failure_message
- #negative_failure_message
require "rack" module ResponseCodeMatchers Rack::Utils::SYMBOL\_TO\_STATUS\_CODE.each do |name, code| name = name.to\_s.gsub("'", "") define\_method("be\_#{name}") do ResponseCodeMatcher.new(code.to\_s, name) end end class ResponseCodeMatcher def initialize(expected, name) @expected = expected @description = name.to\_s.gsub("\_", " ") end def matches?(response) @actual = response.code @actual == @expected end def description "be #@description" end def failure\_message "expected response code to be #@expected, but #@actual" end def negative\_failure\_message "expected response code not to be #@expected, but #@actual" end end end