【RSpec】Capybaraについて

はじめに

 RailsRSpec+Capybraの環境で開発、テストを行っているので、Capybaraについて整理しておきます。

Capybaraとは?

Capybaraは、Webアプリケーションのインテグレーション・テストを補助する為のライブラリです。 Capybaraが提供する本質的な機能としては、DSLとDriverの2点のみです。

DSLドメイン固有言語)

特定の問題に特化したコンピュータ言語です。Capybaraはテスティングフレームワークを操作する命令を、それぞれのフレームワークに依存しない形で提供します。つまり、テスティングフレームワークであるCucumberやRSpec,Test::Unitなどを透過的に利用できます。

ドライバー

Webアプリケーションのインテグレーション・テストには、ブラウザもしくはそれに類するものが必要です。その為に、Seleniumのようにブラウザを操作するフレームワークや、WebKitのようなブラウザのレンダリングエンジンを直接使う方法があります。Capybaraは、それらをドライバとして扱うことが出来ます。

Capybara-DSLのはなし

CapybaraのDSL

画面遷移
メソッド 機能
visit GETページで遷移します

click_link click_bottun click_on

リンクとクリック機能
メソッド 機能
click_link(' id ') ID指定でリンクをクリック
click_link( 'リンクテキスト' ) リンクのテキスト名でクリック
click_button('ボタン名') ボタン名でクリック
click_on( 'テキスト' ) リンクかボタンどちらかをクリック
click_on( ’value' ) ボタンの値指定でクリック
フォーム入力機能
メソッド 機能
visit GETページで遷移します
fill_in('ラベルの名前') それぞれの入力フォームに値を入れる
choose('ラジオボタン') ラジオボタンを選択する
check('チェックボタン') チェックボタンを選択します
uncheck('チェックボタン') チェックボタンの洗濯を外す
attach_file('image', '/path/to/image.jpg') 画像を添付します
select('Option', from: 'Select box') セレクトボックスを選択する

スコープ機能

スコープ機能を利用することで、特定のエレメント下のみ操作できます。

within("li#unique_name") do
  fill_in 'Name', :with => '五十嵐さん'
end

マッチャ

expect(page).to have_content('この文字見つかる') #このページにあるかな?
expect(current_path).to eq(root_path) #パス合ってる? 

別タブに移動して操作する

# 最後に開いたタブに移動している
switch_to_window(windows.last)

参考資料

Capybara-DSLのはなし

【Rails】seed_fuについて

はじめに

 Railsでは、rails db:seedというコマンドがあり、db/seed.rbにシードデータを入れておけば、勝手にシードデータを作成してくれます。しかし、これは1度だけシードデータを作成する場合はよいのですが、シードデータを編集して再度実行すると、同じデータを何個も作成されてしまうという問題点があります。そこで、今回は便利にシードデータを生成してくれるseed-fuというgemを使って、development ,test,productionそれぞれの環境ごとにシードデータを作成する方法を紹介します。

gemの導入とファイルの作成

  • gemの導入
gem  'seed-fu'
$ bundle install

これで、準備完了です。

環境ごとにシードファイルを分ける

 この場合は、fixturesディレクトリの中に、それぞれの環境名ディレクトリを作成し、そこにシードファイルを設置することで実現できます。

Image from Gyazo

シードデータを入れる

 あとは、db/fixtures配下にモデル単位でシードファイルを作成していきます。例えばUserモデルとBoardモデルが合った場合、次のように書きます。

User.seed do |s|
  s.id = 1
  s.name = 'テストユーザー'
  s.email = 'public@example.com'
end
Board.seed do |s|
  s.id = 1
  s.title = 'テストタイトル'
  s.body = 'テスト本文'
  s.user_id = 1
end

上記のファイルを作成したら、rails db:seed_fuでDBにデータが投入されます。 がしかし、これだとエラー発生してしまいます。

Userのデータが入る前に、BoardがUserを参照しようとしてしまっているからです。

シードデータの順番を制御する

 これは簡単でプレフィックスを付けてあげるだけで解決します。

users.rb → 01_users.rb
boards.rb → 02_boards.rb

これだけで、Userからデータを作成してくれて、先ほどの処理が成功します。

【RSpec】モジュールの使用方法について

はじめに

 Rspecモジュールの作成・使用方法について紹介します。

【RSpec】初期設定について

初期設定に加えて

rails_helper

# This file is copied to spec/ when you run 'rails generate rspec:install'
require 'spec_helper'
ENV['RAILS_ENV'] ||= 'test'

Dir[Rails.root.join('spec', 'support', '**', '*.rb')].each { |f| require f } #コメントアウトをはずしましょう

RSpec.configure do |config|

  config.include LoginSupport #ここでsupport配下のものを呼び込んでいます。
  
end

これで、spec/support/配下のものが呼び出せます。

例えば、Loginモジュールを作成できたりします。

login_support.rb(ここの記載はcapybaraを使用しています。)

module LoginSupport
  def login(user)
    visit root_path
    fill_in 'user_name', with: user.name
    click_button '次へ'
    fill_in 'user_password', with: 'password'
    click_button 'ログイン'
  end
end

これで、spec内でモジュールのメソッドが使用でき流ようになります。

【RSpec】Factory_botについて

はじめに

Factory_Botの使用方法について説明します。(gemはインストール済とする)

【RSpec】初期設定について

初期設定

rails_helper.rb

RSpec.configure do |config|
  config.include FactoryBot::Syntax::Methods
end

テストデータの作成方法

Userモデルがある場合、

spec/factories/配下にテストしたい該当モデルのファイルを作成する。 Userモデルならusers.rbという形でファイルを作成する。

spec/factories/users.rb

FactoryBot.define do
  factory :user do
    name { "test" }
    email { "example@com" }
  end
end

このように、ファクトリを作成できます。

テストデータの使用方法

spec/models/users_spec.rb

RSpec.describe User, type: :model do
  let(:user){ FactoryBot.create(:user) } #通常の書き方 DB登録される
  let(:user){ create :user} #省略記法

  let(:user){ FactoryBot.build (:user)} #通常の書き方 DB登録されない
  let(:user){ build :user} #省略記法

  let(:user){ build :user, name: "hogehoge"} #上書きすることも可能
end

traitの使用

 traitを使用することによって、factoryのデータを柔軟に変更できます。例えば、管理者、編集者、記者と分けたい場合はこのように記述します。

users.rb

FactoryBot.define do
  factory :user do
    sequence(:name) { |n| "user-#{n}" }
    password { 'password' }
    password_confirmation { 'password' }
    role { :writer }

    trait :admin do
      sequence(:name) { |n| "admin-#{n}" }
      role { :admin }
    end

    trait :editor do
      sequence(:name) { |n| "editor-#{n}" }
      role { :editor }
    end

    trait :writer do
      sequence(:name) { |n| "writer-#{n}" }
      role { :writer }
    end
  end
end

呼び出すときは、このようにします。

users_spec.rb

RSpec.describe User, type: :model do
  let(:user){ create :user, :writer} 基本データにwriterのnameとroleを上書きする 
 let(:user){ create :user, :admin}  基本データにadminのnameとroleを上書きする 

参考資料

【Rails】factory_botの使い方について

【RSpec】初期設定について

はじめに

 RailsRSpecを導入するときに、初期設定を忘れがちなので備忘録として残しておきます。

gemの追加(rspec)

Gemfile

gem 'rspec-rails'
$ bundle install

これでgemを入れることができました。

設定ファイルを作成するコマンド

$ rails g rspec:install

コマンドを実行すると、下記のファイルが作成されます。

create .rspec
create spec/spec_helper.rb   #RSpecの全体的な設定を書く
create spec/rails_helper.rb  #Rails特有の設定を書く

.rspecの設定

# 出力結果を色分け
--color
# rails_helperの読み込み
--require rails_helper
# 出力結果をドキュメント風に見やすくする
--format documentation

デフォルトだと--require spec_helperとなっているが、RailsRSpecを使う場合は、--require rails_helperを使うのがベターです。

理由としては、後述するrails_helper.rbで既にrequire spec_helperを行なっているためです。

テストデータ生成用のgem(factory_bot)

Gemfile

$ gem 'factory_bot_rails'
$ bundle install

facotory_botのgemを入れることができました。

下記の設定により、FactoryBotのデータ呼び出しを簡略化できます。

spec/rails_helper

require 'spec_helper'
ENV['RAILS_ENV'] ||= 'test'

RSpec.configure do |config|
  
  # FactoryBotの省略
  config.include FactoryBot::Syntax::Methods #ここです
end

この設定をすると、

FactoryBot.create(:user)create(:user)のように簡略化できます。

テストの補助ツール gem(capybara)

Gemfile

gem 'capybara'
$bundle install

spec/spec_helper

RSpec.configure do |config|
 require 'capybara/rspec'
end

で使用できるようになります。

参考資料

RSpecコトハジメ ~初期設定マニュアル~

RailsでRSpecの初期設定を行う際のテンプレートを作ってみる

【Rails】custom predicateについて(ransack)

はじめに

 ransackのcustom predicateとは、name_eqやname_contのeqやcontなどのpredicate(述語)をカスタマイズして、自由に設定できるものです。

実装

まず、config/initializers下にransack.rbファイルを作成しましょう。

公式ドキュメントに下記の記載方法がのっています。

Custom Predicates

# config/initializers/ransack.rb

Ransack.configure do |config|
  config.add_predicate 'equals_diddly', # Name your predicate
    # What non-compound ARel predicate will it use? (eq, matches, etc)
    arel_predicate: 'eq',
    # Format incoming values as you see fit. (Default: Don't do formatting)
    formatter: proc { |v| "#{v}-diddly" },
    # Validate a value. An "invalid" value won't be used in a search.
    # Below is default.
    validator: proc { |v| v.present? },
    # Should compounds be created? Will use the compound (any/all) version
    # of the arel_predicate to create a corresponding any/all version of
    # your predicate. (Default: true)
    compounds: true,
    # Force a specific column type for type-casting of supplied values.
    # (Default: use type from DB column)
    type: :string,
    # Use LOWER(column on database).
    # (Default: false)
    case_insensitive: true
end

一つずつ解説していきます。

# こちらでブロックを作ります。
Ransack.configure do |config|

#ここでpredicateの名前を決めています。これを実際のビューとかで使われるわけですね。
config.add_predicate 'equals_diddly' 

# どんな動きをするかを指定
arel_predicate: 'eq' 

# vが検索されて受け取る値になります。{ |v| "#{v}-diddly" }このブロック内で自分で自由にフォーマットを変えることができます。
formatter: proc { |v| "#{v}-diddly" }

# こちらでバリデーションを決めています。
validator: proc { |v| v.present? } 

# これは恐らく複数のarel_predicateの組み合わせをtrueにするかということだと思います。デフォルトはtrueなので、特にあまりいじらなくて良いかと思います。
compounds: true 

# stringやintegerなどのタイプを指定します。
type: :string 

#  大文字、小文字の区別をする設定です。デフォルトはfalseです。
case_insensitive: true

このような記法で設定していきます。

例えば、

作成日の範囲指定では、掲示板の作成日に対して「◯◯月◯◯日〜◯◯月◯◯日」という検索をかけたいとき、

<%= f.date_field :created_at_gteq, class: 'form-control' %> 〜 
<%= f.date_field :created_at_lteq, class: 'form-control' %> 

これでは、1/1〜1/31日の午前0時まで間しか検索できません。

よって、lteqをカスタマイズします。

ransack.rb

Ransack.configure do |config|
  config.add_predicate 'lteq_end_of_day', # 述語の名前
                                        arel_predicate: 'lteq', #lteqを使用
                                        formatter: proc { |v| v.end_of_day } #上記のものをカスタマイズ
end

これで

<%= f.date_field :created_at_gteq, class: 'form-control' %> 〜 
<%= f.date_field :created_at_lteq_end_of_day, class: 'form-control' %> 

と実装すれば、1/1から1/31日23時59分までの検索をすることができます。

【Rails】gem enum_helpについて

はじめに

 前回、enumについて記事【Rails】enumについてをあげたのですが、それをi18n化する便利なgemがありましたの紹介します。その名も、enum_helpです。

enumi18n対応させよう!!

まず、gemを入れます。

Gemfile

gem 'enum_help'

そして、

$ bundle install

localeファイルに追記

ja:
  enums:
    user:
      role:
        admin: 管理者
        general: 一般

あとは、呼び出すだけです。

   # 管理者user
   # adminに0を設定している
 user.role_i18n
    => '管理者'

     # 一般user
  # generalに1を設定している
 user.role_i18n
    => '一般'

これで、enumi18n化の完了です。 とっても簡単ですね。