Spreeのドキュメントを日本語に訳しました。意訳や怪しい部分もあるのでおかしなところがあればご指摘いただけますと幸いです。
TESTING SPREE APPLICATIONS - DEVELOPER GUIDE | SPREE COMMERCE
概要
Spreeプロジェクトは、現在RSpecでテストが構成されています。Spreeを構成するそれぞれのgemごとに、各コードが正しく動作するようテストスイートがまとめられています。
Spreeのテストコードは発展を続けています。我々は最初、RSpecからはじめ、途中Shouldaに切り替えました。そして現在はまたRSpecに戻っています。RSpecは我々が当初使用したときから大きく改善されていました。Spreeのテストカバー率を上げるべく試行錯誤する中、コミュニティやドキュメントの豊富さに関して圧倒的な勝者となっていたRSpecを見直すに至ったのです。
Spreeの単体テスト
Spreeはいくつかの異なるgemから構成されています。(詳細はソースコードガイドをご覧ください。)それらのgemは、spec
ディレクトリ内にテストコードが格納されています。これらのgemはRailsにより稼働しており、独立した完全な構成ではありません。そのためRailsアプリケーションのコンテキスト内でテストを行う必要があります。
そのようなアプリケーションを構築する場合、テスト用に作られた下記のRakeタスクを使うと便利です。テストをしたい場所でタスクを起動してください。
$ bundle exec rake test_app
このタスクは、spec
ディレクトリ内に適切なテスト用アプリケーションを構築します。またGemfile
にspree_core
gemを追加します(全てのgemがspree_core
に依存しているため)
このrakeタスクは起動するごとに削除したものも含めてアプリケーションを再作成します。またその後にマイグレーションも自動起動されるためテスト用データベースも構築されます。そのためrake db:migrate
やrake db:test:prepare
といったコマンドを起動する必要はありません。
Specの起動
一旦テスト用アプリケーションを構築したら、あとはRSpec標準のルールでテストを起動できます。
$ bundle exec rspec spec
サーバーセットアップ用の模擬スクリプトを使うこともできます。Spreeプロジェクトのルートで下記を起動してください。
$ bash build.sh
単一ファイルのスペックを起動したいときは下記のようにしてください。
$ bundle exec rspec spec/models/spree/state_spec.rb
特定行のテストを実行したいときはこのようにしてください。
$ bundle exec rspec spec/models/spree/state_spec.rb:7
Factoriesの使用
Spreeはfactory_girl
をテスト用レコードの作成に使用しています。全てのファクトリはgem内に格納されています。そのためエクステンションを作成する場合や、Spreeモデルを実行したい場合には次のようにすることでこれらのファクトリを使用できます。
$ rails console
$ require 'spree/testing_support/factories'
spree_core
gemは、テストに使用できるかなりの数のファクトリを含んでいます。エクステンションを作る際やSpreeをテストする際にこれらを使用できます。
作成したSpreeアプリケーションのテスト
現在のところ、Spreeはあなたのアプリケーションにインストールして使用できるテストを提供していません。我々のアドバイスとしては、Spreeコンポーネントからテストをコピーしたものを必要に応じて書き換えて使用することをおすすめします。
ユニットテスト
Spreeフレームワークをインストールした直後には、個別にテストを作らなくともSpreeそのものには十分なユニットテストが施されています。
Spreeのコードの書き換えを行う場合には、そのエクステンションや変更をカバーできるユニットテストを追加するべきでしょう。
インテグレーションテスト
以前、Railsデベロッパーはフィクスチャやシードデータを好んでいました。しかしアプリケーションが大きくなるにつれてフィクスチャやシードデータからファクトリへ移行してきました。
ファクトリは固有の問題を持つとされてきましたが、現在では大きなフィクスチャ/シードデータをセットアップするよりも優れていると広く考えられています。このことについてはこのブログ記事にて論じられています。
下記は、ファクトリ(FactoryGirl)を使ってどのようにテストを作るかの例です。前述の通り、SpreeCoreからSpreeのファクトリを全てコピーすることもできます。もしくは自身でファクトリを書くことも可能です。
チェックアウト周りの部分のインテグレーションテストは完全にカバーすることをおすすめしています。またAdminエリアについてもインテグレーションテストを書くことができますが、殆どの人はそれをしません。なぜならエンドユーザーが直面する部分ではないからです。ユニットテストと同様、最重要なのはデフォルトのSpreeと異なるあなたのSpreeストアの部分です。
ログイン状態のテスト
もしあなたがspree_auth_devise
を使っているならば、あなたのアプリケーションにはWarden gem
が既に組み込まれており、ログイン状態のテストに使用することができます。
let(:user) { FactoryGirl.create(:user) }
before(:each) do
login_as(user, :scope => :spree_user)
end
これでログインしているユーザーとしての振る舞いとなります。
非ログイン状態のテスト
Spree 2.2かそれ以前では、Spreeはログアウト状態のユーザーの注文を見失わないためにセッション変数を使用していました。これはSpree2.2以前で動作する例です。
let (:order) { FactoryGirl.create(:order) }
before(:each) do
page.set_rack_session(:order_id => order.id)
page.set_rack_session(:access_token => order.token)
end
Spree2.3では、署名付きクッキーをゲストユーザーのカートに使用しています。次の例では、ゲストトークンを模造するためSpree内で2つのスタブを作成しています(テキストはわかりやすいように「xyz」としています)例えばOrderファクトリは「Some Product」と呼ばれるproductと紐づくLineitemを持っています。
describe “cart to registration page”, :type => :feature do
let(:order) { FactoryGirl.create(:order, :guest_token => “xyz”) }
# user should be nil for logged out user
describe “as someone not logged in” do
before(:each) do
order SecureRandom.stub!(:urlsafe_base64) .with(any_args) .and_return(“xyz”)
Spree::OrdersController.any_instance
.stub(:cookies)
.and_return(mock(:cookies, :signed => {:guest_token => "xyz"}))
end
it "should let me load the shopping cart page" do
visit '/cart'
page.status_code.should eq(200)
expect(page).to have_content 'Some Product'
end
end
TODO
我々はRackTest driver内に署名済みクッキーをセットする方法を探しています。もしそれができれば、コード例のSpree::OrdersControllerからスタブを取り除くことが可能となります。
Thomas Walpoleは、コードが次のようになると考えています。しかしまだ正しく動くまでには至っていません。
kg = ActiveSupport::KeyGenerator.new(Rails.application.secrets.secret_key_base, iterations:1000)
guest_token_cookie_value_to_set = ActiveSupport::MessageVerifier.new(kg.generate_key("signed cookie"), digest: 'SHA1', serializer: ActiveSupport::MessageEncryptor::NullSerializer).generate("\"#{guest_token}\"")