【初心者向け】deviseのユーザー登録をRSpecでテストする

# はじめに
deviseを導入したは良いものの最初のテストが書けない…！どうやって書いたらいいの、というとこで情報がまとまってなかったので自分でまとめてみました。
自分でアプリを作り始めた初心者さん向けです。

Ruby   '2.6.6'
Rails '5.2.4'


# 1.Gemfileの編集

```ruby:Gemfile
group :development, :test do
・
・
  gem "rspec-rails"
  gem "factory_bot_rails"
end
```
をGemfileに加える


```ruby:Terminal
bundle install
```



```ruby:Terminal

bundle install 
Fetching gem metadata from https://rubygems.org/............. 
Fetching gem metadata from https://rubygems.org/. 
・
・
Using duktape 2.3.0.0 
Fetching factory_bot 6.1.0 
Installing factory_bot 6.1.0 
Fetching factory_bot_rails 6.1.0 
Installing factory_bot_rails 6.1.0 
Using jbuilder 2.10.0
・
・
Using web-console 3.7.0 
Bundle complete! 22 Gemfile dependencies, 95 gems now installed. 
Use `bundle info [gemname]` to see where a bundled gem is installed.

```


RSpecをダウンロードする

```ruby:Terminal
$ bundle exec rails generate rspec:install
```


# 2. rspecの設定


.rspecに以下の記述を行います。


```ruby:rspec
--require spec_helper
--format documentation #ここを追加
```



>上の記述はあってもなくてもいいのですが、あるなしでテスト実行時の表示がこのくらい変わります。

```
なし
＄ ...............................

あり
$ User
$ #create
$   is valid
$   is invalid without email
$   is invalid without password 
```

引用元：rspecのテスト環境でdeviseにログインする方法【rails】
https://qiita.com/Kohei_Kishimoto0214/items/e29e509b12a6eb484a42

### なにも書いて無いけど試しにテストしてみる

テストするコマンドは
`bundle exec rspec`
または、個別に指定することもできる

```ruby:Terminal
bundle exec rspec
No examples found.


Finished in 0.00101 seconds (files took 3.71 seconds to load)
0 examples, 0 failures

```

まだ確認することは記述してないですが、表示はされています…！！！

# 3.Factory_botの設定をする

`rails_helper.rb`内のconfigの部分に以下の記述を追加します。

```spec/rails_helper.rb
RSpec.configure do |config|
    config.includeFactoryBot::Syntax::Methods
end
```


こんな感じになると思います。

```spec/rails_helper.rb
RSpec.configure do |config|
  # Remove this line if you're not using ActiveRecord or ActiveRecord fixtures
  config.fixture_path = "#{::Rails.root}/spec/fixtures"
  config.include FactoryBot::Syntax::Methods
  config.use_transactional_fixtures = true
  config.infer_spec_type_from_file_location!
  config.filter_rails_from_backtrace!
end
```

# 4.rails_helperの設定


次に、`/spec/rails_helper.rb`内で以下の一文がコメントアウトされているので、コメントアウトを外してください。
これで`spec/support/`のファイルを読み込むことができます。


```/spec/rails_helper.rb
Dir[Rails.root.join('spec/support/**/*.rb')].each{|f|requiref}
```


```/spec/rails_helper.rb
# This file is copied to spec/ when you run 'rails generate rspec:install'
require 'spec_helper'
ENV['RAILS_ENV'] ||= 'test'
require File.expand_path('../config/environment', __dir__)
# Prevent database truncation if the environment is production
abort("The Rails environment is running in production mode!") if Rails.env.production?
require 'rspec/rails'
# Add additional requires below this line. Rails is not loaded until this point!

# Requires supporting ruby files with custom matchers and macros, etc, in
# spec/support/ and its subdirectories. Files matching `spec/**/*_spec.rb` are
# run as spec files by default. This means that files in spec/support that end
# in _spec.rb will both be required and run as specs, causing the specs to be
# run twice. It is recommended that you do not name files matching this glob to
# end with _spec.rb. You can configure this pattern with the --pattern
# option on the command line or in ~/.rspec, .rspec or `.rspec-local`.
#
# The following line is provided for convenience purposes. It has the downside
# of increasing the boot-up time by auto-requiring all files in the support
# directory. Alternatively, in the individual `*_spec.rb` files, manually
# require only the support files necessary.
#
 Dir[Rails.root.join('spec', 'support', '**', '*.rb')].sort.each { |f| require f }　　ここのコメントアウトを外した

# Checks for pending migrations and applies them before tests are run.
# If you are not using ActiveRecord, you can remove these lines.
begin
  ActiveRecord::Migration.maintain_test_schema!
rescue ActiveRecord::PendingMigrationError => e
  puts e.to_s.strip
  exit 1
end
RSpec.configure do |config|
  # Remove this line if you're not using ActiveRecord or ActiveRecord fixtures
  config.fixture_path = "#{::Rails.root}/spec/fixtures"
  config.include FactoryBot::Syntax::Methods
  

  # If you're not using ActiveRecord, or you'd prefer not to run each of your
  # examples within a transaction, remove the following line or assign false
  # instead of true.
  config.use_transactional_fixtures = true

  # You can uncomment this line to turn off ActiveRecord support entirely.
  # config.use_active_record = false

  # RSpec Rails can automatically mix in different behaviours to your tests
  # based on their file location, for example enabling you to call `get` and
  # `post` in specs under `spec/controllers`.
  #
  # You can disable this behaviour by removing the line below, and instead
  # explicitly tag your specs with their type, e.g.:
  #
  #     RSpec.describe UsersController, type: :controller do
  #       # ...
  #     end
  #
  # The different available types are documented in the features, such as in
  # https://relishapp.com/rspec/rspec-rails/docs
  config.infer_spec_type_from_file_location!

  # Filter lines from Rails gems in backtraces.
  config.filter_rails_from_backtrace!
  # arbitrary gems may also be filtered via:
  # config.filter_gems_from_backtrace("gem name")
end
```

# 5.テストデータの準備


新しいフォルダ＆ファイル`spec\factories\user.rb`を作成

今回、Fakerは入れてないので、手動でデータ入力をします。
通し番号を振っていく付け方もありますが、今回は一番シンプルな方法にします。

devise初期設定は名前がないので以下の3要素のみ必要です。
nameカラムを追加している方は`spec\factories\user.rb`にもnameの項目を追加して下さい。


```spec\factories\user.rb
FactoryBot.define do
  factory :user do
    email                 {"test@gmail.com"}
    password              {"111111"}
    password_confirmation {"111111"}
  end
end
```

# 6.controller_macrosの作成

`spec/support/controller_macros.rb`を作成し、下記の公式の内容を追記してください。

公式：How To: Test controllers with Rails (and RSpec)
https://github.com/heartcombo/devise/wiki/How-To:-Test-controllers-with-Rails-(and-RSpec)



```spec/support/controller_macros.rb
module ControllerMacros
  def login_admin
    before(:each) do
      @request.env["devise.mapping"] = Devise.mappings[:admin]
      sign_in FactoryBot.create(:admin) # Using factory bot as an example
    end
  end

  def login_user
    before(:each) do
      @request.env["devise.mapping"] = Devise.mappings[:user]
      user = FactoryBot.create(:user)
      user.confirm! # or set a confirmed_at inside the factory. Only necessary if you are using the "confirmable" module
      sign_in user
    end
  end
end
```


# 7. rails_helper内でdeviseとcontroler_macrosを読み込む


rails_helperのRSpec.configure外に以下を記述し、deviseとmacrosを読み込みます。
	

```spec/rails_helper.rb
require'devise'
require File.expand_path("spec/support/controller_macros.rb")
```

RSpec.configure内に以下を記述し、deviseのtest_helperとmacrosをcontroller内で使えるようにします。
	

```spec/rails_helper.rb
RSpec.configure do |config|
・
・
 config.include Devise::Test::ControllerHelpers, type: :controller
  config.include Devise::Test::IntegrationHelpers, type: :request
  config.extend ControllerMacros, :type => :controller
・
・
```


加えるとこんな感じになります。
　

```spec\rails_helper.rb

 # This file is copied to spec/ when you run 'rails generate rspec:install'
require 'spec_helper'
ENV['RAILS_ENV'] ||= 'test'
require File.expand_path('../config/environment', __dir__)
abort("The Rails environment is running in production mode!") if Rails.env.production?
require 'rspec/rails'
require 'devise'
require File.expand_path("spec/support/controller_macros.rb")
require_relative 'support/controller_macros'

 Dir[Rails.root.join('spec', 'support', '**', '*.rb')].sort.each { |f| require f }


begin
  ActiveRecord::Migration.maintain_test_schema!
rescue ActiveRecord::PendingMigrationError => e
  puts e.to_s.strip
  exit 1
end
RSpec.configure do |config|
  # Remove this line if you're not using ActiveRecord or ActiveRecord fixtures
  config.fixture_path = "#{::Rails.root}/spec/fixtures"
  config.include FactoryBot::Syntax::Methods
  config.include Devise::Test::ControllerHelpers, type: :controller
  config.include Devise::Test::IntegrationHelpers, type: :request
  config.extend ControllerMacros, :type => :controller

 
  config.infer_spec_type_from_file_location!
  config.filter_rails_from_backtrace!

end
```


# 8. user_spec.rbで、userをcreateしログイン処理をする

createしたuserをletに格納しインスタンス変数のように使用できるようにしました。
さらにそのuserにlogin_userメソッドを使ってdeviseにログインさせます。



modelのvalidationをテストします。
事前にvalidationは設定してください。


```spec\models\user_spec.rb
require 'rails_helper'

RSpec.describe User, type: :model do
    describe 'ユーザー登録' do
     it "name、email、passwordとpassword_confirmationが存在すれば登録できること" do
       user = build(:user)
       expect(user).to be_valid  # user.valid? が true になればパスする
     end

end
```
>
>引用元：[Rspecを使用したテスト①(単体テスト：バリデーションのテスト)]
(https://misukeblog.com/rspec/)
引用元：[Rspecを使用したテスト②(統合テスト)]
(https://misukeblog.com/rspec2/)

かいてからの

```ruby:Terminal
bundle exec rspec
```
でいける

はず！！！！これで完成！！

```ruby:Terminal
$ bundle exec rspec
 
User
  name、email、passwordとpassword_confirmationが存在すれば登録できること        
 
Finished in 0.5297 seconds (files took 9.34 seconds to load)
1 example, 0 failures

```


# 9.ハマったところ

### パターン1

```ruby:Terminal

& rails g rspec:model user
    conflict  spec/models/user_spec.rb
Overwrite C:/Users/.../ (アプリ名) /spec/models/user_spec.rb? (enter "h" for help) [Ynaqdhm]
 force  spec/models/user_spec.rb   for help) [Ynaqdhm]
$ bundle 


Migrations are pending. To resolve this issue, run:
 
        bin/rails db:migrate RAILS_ENV=test
No examples found.

```

こんな時は指示通り

```ruby:Terminal
$ rails db:migrate RAILS_ENV=test
```
しましょう

### パターン2

こんなエラーがでたらそれはgemfileの中に古いGemが混ざっています。

```ruby:Terminal

$ bundle exec rspec
2020-09-02 22:36:39 WARN Selenium [DEPRECATION] Selenium::WebDriver::Chrom
e#driver_path= is deprecated. Use Selenium::WebDriver::Chrome::Service#dri
ver_path= instead.
 
An error occurred while loading ./spec/models/user_spec.rb.
Failure/Error: require File.expand_path('../config/environment', __dir__)
 
Selenium::WebDriver::Error::WebDriverError:
per-2.1.1/bin/chromedriver-helper"
# ./config/application.rb:7:in `<top (required)>'

# ./config/environment.rb:2:in `<top (required)>'
# ./spec/rails_helper.rb:4:in `require'
# ./spec/rails_helper.rb:4:in `<top (required)>'
# ./spec/models/user_spec.rb:1:in `require'
# ./spec/models/user_spec.rb:1:in `<top (required)>'
No examples found.
 
 
Finished in 0.00008 seconds (files took 7.23 seconds to load)
0 examples, 0 failures, 1 error occurred outside of examples

```


参考：Rspecが動かない　rails_helperの読み込み
https://teratail.com/questions/247938?link=qa_related_pc

Gemfileを書き換えます。

```ruby:Gemfile

group :test do
  # Adds support for Capybara system testing and selenium driver
  gem 'capybara', '>= 2.15'
  gem 'selenium-webdriver'
  # Easy installation and use of chromedriver to run system tests with Chrome
  #gem 'chromedriver-helper'　　#この1文を削除orコメントアウト
  gem 'webdrivers', '~> 3.0'　#この1行を追加
  gem 'rspec-rails'
  gem "factory_bot_rails"
end
・
・

gem 'devise'
```


そして

```ruby:Terminal
bundle install
```

これでいけるはずです！


# 最後に
間違いなどがあればご指摘いただけると嬉しいです。

#いろいろな参考
[RailsアプリへのRspecとFactory_botの導入手順]
(https://qiita.com/Ushinji/items/522ed01c9c14b680222c)

[RSpec初心者のdevise認証システムテスト]
(https://qiita.com/zongxiaojie/items/d488edd42ba3864859c7)

[rspecのテスト環境でdeviseにログインする方法【rails】]
(https://qiita.com/Kohei_Kishimoto0214/items/e29e509b12a6eb484a42)

[deviseを使ったコントローラのテスト]
(https://qiita.com/nysalor/items/ef3d658ff76bee165379)

[RSpecを用いた単体テストについての備忘録 @TECH CAMP #11　-note]
(https://note.com/ruquia7/n/n00ff04fc9129)

[[Ruby on Rails]rspecを用いたmodelの単体テスト　-note]
(https://note.com/vixer93/n/n6ef6555d7a3e)

[Railsでmigrate後のエラー「bin/rails db:migrate RAILS_ENV=test」について]
(https://teratail.com/questions/178462)