テスト

花見は、コードのテスト容易性に多くの注目を支払い、それが私たちの生活を容易にするための高度な機能を提供しています。フレームワークは、Minitest(デフォルト)とRSpecのをサポートしています。

 

ユニットテスト

まず第一に、アクションは、ユニットを試験することができます。それは我々が、インスタンス化運動と期待を確認することができることを意味アクションインスタンス上で直接

# spec/web/controllers/dashboard/index_spec.rb
require 'spec_helper'
require_relative '../../../../apps/web/controllers/dashboard/index'

describe Web::Controllers::Dashboard::Index do
  let(:action) { Web::Controllers::Dashboard::Index.new }
  let(:params) { Hash[] }

  it "is successful" do
    response = action.call(params)
    response[0].must_equal 200
  end
end

上記の例では、actionインスタンスでありWeb::Controllers::Dashboard::Index、我々は呼び出すことができる#callパラメータのハッシュを渡し、その上に。暗黙の返却値は、シリアル化されたラックの応答です。私たちは、ステータスコードが(と主張しているresponse[0])(に等しい成功しています200)。

 

テストの実行

私たちは、全体のテストスイートまたは1つのファイルを実行することができます。

アプリケーションのデフォルトのrakeタスクは、私たちの最初のケースのために機能します:bundle exec rake。すべての依存関係とアプリケーションコード(アクション、ビュー、実体、などが..)熱心にロードされます。
起動時間は、この場合では遅いです。

全体のテストスイートは、デフォルトのrakeタスクを経由して実行することができます。それはすべての依存関係、およびアプリケーション・コードをロードします。

:2番目のシナリオを介して行うことができるruby -Ispec spec/web/controllers/dashboard/index_spec.rb(またはrspec spec/web/controllers/dashboard/index_spec.rb、我々はRSpecのを使用している場合)。我々は、単一のファイルの例を実行する場合のみフレームワークとアプリケーションの設定がロードされます

ご注意require_relative例の行を。それはです私たちのために自動生成し、テスト中の現在のアクションをロードするために必要なの。このメカニズムは、私たちは中にユニットテストを実行することを可能にする分離
起動時間が速く大きさです

単一のユニットテストを直接実行することができます。これは、依存関係のみではなく、アプリケーション・コードをロードします。テスト対象のクラスを介してロードされrequire_relative、自動的に私たちのために生成された行、。このように、我々は、より高速な起動時間と短いフィードバックサイクルを持つことができます。

 

PARAMS

アクションをテストする場合、我々は簡単にリクエストから来パラメータとヘッダをシミュレートすることができます。私達はちょうどハッシュとしてそれらを渡す必要があります。などラックENVのヘッダーHTTP_ACCEPT等のparamsと混合することができます:id

以下の試験例では、両方を使用します。

# spec/web/controllers/users/show_spec.rb
require 'spec_helper'
require_relative '../../../../apps/web/controllers/users/show'

describe Web::Controllers::Users::Show do
  let(:action)  { Web::Controllers::Users::Show.new }
  let(:format)  { 'application/json' }
  let(:user_id) { '23' }

  it "is successful" do
    response = action.call(id: user_id, 'HTTP_ACCEPT' => format)

    response[0].must_equal                 200
    response[1]['Content-Type'].must_equal "#{ format }; charset=utf-8"
    response[2].must_equal                 ["ID: #{ user_id }"]
  end
end

ここでは、対応する製品コード。

# apps/web/controllers/users/show.rb
module Web::Controllers::Users
  class Show
    include Web::Action

    def call(params)
      puts params.class # => Web::Controllers::Users::Show::Params
      self.body = "ID: #{ params[:id] }"
    end
  end
end

リクエストパラメータとヘッダをシミュレートする花見アクションのために簡単です。私たちは、として渡すHashと、彼らはのインスタンスに変換されますHanami::Action::Params

 

エクスポージャー

私たちは、アクションの内部状態を確認したい場合があります。上記の例に示したように、我々は、古典的なユーザーのプロフィールページを持っている想像してみてください。アクションは、指定されたIDに対応するレコードを要求し、その後設定@userインスタンス変数を。どのように我々はレコードが、我々が探しているものであることを確認しますか?

私たちが作りたいので@user、外の世界に利用できる、我々は使用するつもりの露出を。それらは、アクションと対応するビューの間のデータペイロードを渡すために使用されます。私たちが行うとexpose :user、花見は(ゲッターを作成します#user)、そのレコードが正しいものであるならば、我々は簡単に主張することができます。

# apps/web/controllers/users/show.rb
module Web::Controllers::Users
  class Show
    include Web::Action
    expose :user, :foo

    def call(params)
      @user = UserRepository.new.find(params[:id])
      @foo  = 'bar'
    end
  end
end

我々は2つの使用しているエクスポージャーを:userし、:fooそれらが正しく設定されている場合のは確認してみましょう。

# spec/web/controllers/users/show_spec.rb
require 'spec_helper'
require_relative '../../../../apps/web/controllers/users/show'

describe Web::Controllers::Users::Show do
  before do
    @user = UserRepository.new.create(name: 'Luca')
  end

  let(:action)  { Web::Controllers::Users::Show.new }

  it "is successful" do
    response = action.call(id: @user.id)

    response[0].must_equal 200

    action.user.must_equal @user
    action.exposures.must_equal({user: @user, foo: 'bar'})
  end
end

アクションの内部状態を容易に確認することができエクスポージャー

 

依存性注入

ユニットテスト中に、我々はより速くテストを行うことやデータベース、ファイル・システムまたはリモートサービスのような外部システムを打撃を避けるためにモックを使用することをお勧めします。私たちは試験中のアクションをインスタンス化することができるので、テストのアンチパターンを使用する必要はありません(例えばany_instance_of、またはUserRepository.new.stub(:find))。代わりに、私達はちょうど私たちが経由して使用したいの協力者を指定することができます依存性注入

それはデータベースにヒットしないようにのは、上記のテストを書き直してみましょう。私たちは、それはモック(ダブルス)のためのよりよいAPIを持っているように、この例のためにRSpecのを使用するつもりです。

# spec/web/controllers/users/show_spec.rb
require 'spec_helper'
require_relative '../../../../apps/web/controllers/users/show'

RSpec.describe Web::Controllers::Users::Show do
  let(:action)     { Web::Controllers::Users::Show.new(repository: repository) }
  let(:user)       { User.new(id: 23, name: 'Luca') }
  let(:repository) { double('repository', find: user) }

  it "is successful" do
    response = action.call(id: user.id)

    expect(response[0]).to      eq 200
    expect(action.user).to      eq user
    expect(action.exposures).to eq({user: user})
  end
end

我々は、我々の場合はモックでリポジトリ依存関係を注入しています。ここに私たちの行動をどのように適合させますか。

# apps/web/controllers/users/show.rb
module Web::Controllers::Users
  class Show
    include Web::Action
    expose :user

    def initialize(repository: UserRepository.new)
      @repository = repository
    end

    def call(params)
      @user = @repository.find(params[:id])
    end
  end
end

ユニットテストでダブルスを使用して注意してください。常にモックは、対応する製品コードの真の表現であることを確認します。

 

依頼試験

ユニットテストは予想通りの低レベルのインタフェースが動作することを主張するのに最適なツールです。我々は常に統合テストとそれらを組み合わせることをお勧めします。

花見のWebアプリケーションの場合は、我々はカピバラで(受け入れテスト別名)機能を書くことができますが、私たちはHTTP APIを構築しているとき、私たちは何を使うのですか?我々が提案するツールですrack-test

想像してみて、私たちは、APIアプリケーションがでマウントしている/api/v1私たちにHanami::Container

# config/environment.rb
# ...
Hanami::Container.configure do
  mount ApiV1::Application, at: '/api/v1'
  mount Web::Application,   at: '/'
end

その後、我々は、以下の作用を有します。

# apps/api_v1/controllers/users/show.rb
module ApiV1::Controllers::Users
  class Show
    include ApiV1::Action
    accept :json

    def call(params)
      user = UserRepository.new.find(params[:id])
      self.body = JSON.generate(user.to_h)
    end
  end
end

このケースでは、アクションの内部状態についてはあまり気にしませんが、外部世界への出力について見えます。我々が設定していない理由はここにあるuserインスタンス変数として、なぜ我々はそれを暴露していません。

# spec/api_v1/requests/users_spec.rb
require 'spec_helper'

describe "API V1 users" do
  include Rack::Test::Methods

  before do
    @user = UserRepository.new.create(name: 'Luca')
  end

  # app is required by Rack::Test
  def app
    Hanami.app
  end

  it "is successful" do
    get "/api/v1/users/#{ @user.id }"

    last_response.must_be :ok?
    last_response.body.must_equal(JSON.generate(@user.to_h))
  end
end

避けてくださいテストダブルを、我々は予想通りスタック全体が動作していることを確認したいと、完全な統合テストを書くとき。