action_controllerの拡張gemをRSpecでTDD ٩( ‘ω’ )و
action_controllerの拡張gemを作成するときにrspecでテストする
ユーザ認証のサンプルgemをTDDで作っていきましょう
まずは、gemのひな形を作る
$ bundle gem user_auth
bundlerが1.9系なら以下のファイルが作成されてるはず
├── Gemfile ├── LICENSE.txt ├── README.md ├── Rakefile ├── bin │ ├── console │ └── setup ├── lib │ ├── user_auth │ │ └── version.rb │ └── user_auth.rb ├── spec │ ├── spec_helper.rb │ └── user_auth_spec.rb └── user_auth.gemspec
さて、ここから本題です
ゴールはこんな感じで、認証に失敗したら例外みたいなー
class ApplicationControlller < ActionController::Base before_action :authenticate_user! end
TDDなのでテストから書いてくが、その前に開発時に必要なgemをインストール
# Gemfile source 'https://rubygems.org' gemspec # この3つを追加 gem 'rails' gem 'rspec-rails' gem 'sqlite3'
ざっとテスト書いていきまーす
# spec/user_authenticate_spec.rb require 'spec_helper' RSpec.describe UserAuth::UserAuthenticate do describe ApplicationController, type: :controller do controller do def index render text: 'success!' end end context 'Authentication failure' do example do expect { get :index }.to raise_error end end context 'Authentication success' do let(:user) { User.create(email: 'user@example.com') } example do session[:user_id] = user.id get :index expect(response.body).to eq 'success!' end end end end
テスト実行すると落ちます!
uninitialized constant UserAuth::UserAuthenticate (NameError)
UserAuthenticateがないよーって言ってるので作りましょう
# lib/user_auth/user_authenticate.rb module UserAuth module UserAuthenticate end end # spec/spec_helper.rb $LOAD_PATH.unshift File.expand_path('../../lib', __FILE__) require 'user_auth' # 追加 require 'user_auth/user_authenticate'
テストを実行!
uninitialized constant ApplicationController (NameError)
ApplicationControllerがないって言ってるので、ダミーのコントローラーを作ります
# spec/support/action_controller.rb require 'action_controller/base' class ApplicationController < ActionController::Base end # spec/spec_helper.rb $LOAD_PATH.unshift File.expand_path('../../lib', __FILE__) require 'user_auth' # 追加 require 'support/action_controller'
テストを実行!
'method_missing': undefined method 'controller'
RSpecのcontrollerメソッドがないっていってる。
これはrspec-railsのメソッドなので、spec_helperに追加
# spec/spec_helper.rb $LOAD_PATH.unshift File.expand_path('../../lib', __FILE__) require 'user_auth' require 'support/action_controller' # 追加 require 'rspec/rails'
テストを実行!
undefined method 'application' for Rails:Module
applicationがないって言ってるのでダミーのRails::Applicationを作ります
# spec/support/application.rb require 'action_dispatch' module Rails class App def env_config; {} end def routes return @routes if defined? @routes @routes = ActionDispatch::Routing::RouteSet.new @routes.draw do resources :posts end @routes end end def self.application @app ||= App.new end end # spec/spec_helper.rb $LOAD_PATH.unshift File.expand_path('../../lib', __FILE__) require 'user_auth' # action controllerより前に追加 require 'support/application' require 'support/action_controller' require 'rspec/rails'
テストを実行!
uninitialized constant User
Userがないって言ってるのでダミーのUserモデルを作ります
# spec/support/active_record.rb require 'active_record' ActiveRecord::Base.establish_connection(adapter: 'sqlite3', database: ':memory:') class User < ActiveRecord::Base; end class CreateAllTables < ActiveRecord::Migration def self.up create_table :users do |t| t.string :email end end end # spec/spec_helper.rb $LOAD_PATH.unshift File.expand_path('../../lib', __FILE__) require 'user_auth' require 'user_auth/user_authenticate' require 'support/application' require 'support/action_controller' require 'rspec/rails' # 追加 require 'support/active_record' RSpec.configure do |config| config.before :all do CreateAllTables.up unless ActiveRecord::Base.connection.table_exists? 'users' end config.before :each do User.delete_all end end
テストを実行!
For instance, 'include Rails.application.routes.url_helpers'.
そのまま、ダミーのApplicationControllerにincludeしてあげましょう
# spec/support/action_controller.rb require 'action_controller' class ApplicationController < ActionController::Base include Rails.application.routes.url_helpers end
テストを実行!
expected Exception but nothing was raised
キタ——(゚∀゚)——!!
ダミーのApplicationControllerにauthenticate_user!メソッドを追加しましょう
# spec/support/action_controller.rb require 'action_controller' class ApplicationController < ActionController::Base include Rails.application.routes.url_helpers before_action :authenticate_user! end
テストを実行!
undefined method 'authenticate_user!'
authenticate_user!メソッドを実装します
# lib/user_auth/user_authenticate.rb module UserAuth module UserAuthenticate def authenticate_user! end end end # lib/railtie.rb require 'rails/railtie' require 'active_support' module UserAuth class Railtie < Rails::Railtie ActiveSupport.on_load :action_controller do require 'user_auth/user_authenticate' send :include, UserAuth::UserAuthenticate end end end # lib/user_auth.rb require "user_auth/version" # 追加 require 'user_auth/railtie' ...
テストを実行!
expected Exception but nothing was raised
authenticate_user!メソッドでユーザを取得する
# lib/user_auth/user_authenticate.rb module UserAuth module UserAuthenticate def authenticate_user! User.find(session[:user_id]) end end end
テストを実行!
おーるぐりーんヾ( ̄∇ ̄=ノ
どうですか?
TDDなら次に何をするかが明確になりますよね?
テストを書いて、エラーがでたら原因を調べて解消していく
テストが失敗(エラーじゃないよ)したらロジックを書く!
そしてグリーンになればオッケーって感じです
サンプルコードは雑ですがね...
Happy Hacking٩( ‘ω’ )و