2017年6月17日土曜日

独自のコントローラクラスを作成している sinatra を rspec でテストする

概要

Sinatra::Base を継承して独自のコントローラクラスを作成している場合に rspec を使ってテストする方法を紹介します
少し工夫が必要でした

環境

  • CentOS 7.3.1611
  • ruby 2.3.3p222
  • rspec 3.6.0
  • sinatra 1.4.8

インストール

  • bundle init
  • vim Gemfile
gem "sinatra"
gem "rspec"
gem "rack-test"
  • bundle install

独自のコントローラクラスの作成

  • vim app.rb
require 'sinatra/base'

class MyApp < Sinatra::Base
  get '/' do
    'myapp'
  end
end

このクラス内でアプリを起動 (run) することはしません

rackup で起動させる

  • vim config.ru
require 'bundler'
Bundler.require

require './app'
run MyApp

これで rackup コマンドで MyApp アプリケーションが起動します
こうすることで独自のコントローラクラスを切り離しテストし易いようにします
もし MyApp 内で run! をしてしまうと rspec でテストを実行したときにアプリケーションが起動してしまいテストが進まなくなってしまいます

今回は直接アプリを起動しませんがもし起動させたい場合は

  • bundle exec rackup

で 127.0.0.1:9292 で起動します

テストの作成

  • rspec --init
  • vim spec/app_spec.rb
# -*- coding: utf-8 -*-
ENV['RACK_ENV'] = 'test'

require './app.rb'
require 'rspec'
require 'rack/test'

describe "MyApp のテスト" do
  include Rack::Test::Methods

  def app
    MyApp
  end

  it "root にアクセスしたときに myapp を返却する" do
    get '/'
    expect(last_response.status).to eq 200
    expect(last_response.body).to eq 'myapp'
  end
end
  • bundle exec rspec -f d spec/
MyApp のテスト
  root にアクセスしたときに myapp を返却する

Finished in 0.02609 seconds (files took 0.18599 seconds to load)
1 example, 0 failures

こんな感じになれば成功です

おまけ spec_helper.rb を使って記述を楽にする

今のままだと describe するたびに include して def しなければなりません
そんなときに spec_helper.rb を使って設定しておくと省略することができます

  • vim spec/spec_helper.rb
ENV['RACK_ENV'] = 'test'

require File.expand_path '../../app.rb', __FILE__
require 'rack/test'
require 'rspec'

module RSpecMixin
  include Rack::Test::Methods

  def app
    MyApp
  end
end

RSpec.configure do |config|
  config.include RSpecMixin
  config.expect_with :rspec do |expectations|
    expectations.include_chain_clauses_in_custom_matcher_descriptions = true
  end

  config.mock_with :rspec do |mocks|
    mocks.verify_partial_doubles = true
  end

  config.shared_context_metadata_behavior = :apply_to_host_groups
end

デフォルトのコメントはすべて削除しました
要するにテスト内でやっていた処理を module 化して、それを Rspec.configure にあらかじめ設定してあげる感じです

テスト側は以下のように変更します

  • vim spec/app_spec.rb
# -*- coding: utf-8 -*-
require File.expand_path '../spec_helper.rb', __FILE__

describe "MyApp のテスト" do
  it "root にアクセスしたときに myapp を返却する" do
    get '/'
    expect(last_response.status).to eq 200
    expect(last_response.body).to eq 'myapp'
  end
end

かなりすっきりしました
冒頭で spec_helper.rb を require するだけになります

あとは同じようにテストを実行すれば OK です

  • bundle exec rspec -f d spec/

最後に

Sinatra で独自のコントローラクラスを定義している場合に rspec でテストする方法を紹介しました
ポイントはアプリケーションの起動を rackup を使うということでした

参考サイト

0 件のコメント:

コメントを投稿