Posts Rspecのインストールとテストの基本
Post
Cancel

Rspecのインストールとテストの基本

Rspecでビヘイビア(振舞)駆動開発をしよう。そこでRspecをインストールしRspecでモデルのテストをしてみます。

登録されたユーザーはログインができます。そのログインユーザーには権限があり、その権限によってできること/できないことがあることを想定しています。そこでユーザー権限「Role」を作ります。

今回は以下の流れになります。

  1. rspec-rails、database_cleaner、factory_girl_railsのインストールと設定

  2. ユーザ権限Roleモデルを作成

  3. FactoryGirlsでログインユーザー(管理者と一般ユーザー)の権限(Role)を作成

  4. Roleモデルをテスト

Rspec をインストール

テストデータ(だけに限定されるわけではありませんが)を登録するのに便利な gem「factory_girl_rails」と、テストを実行後データベースを初期状態に戻してくれる gem「database_cleaner」もインストールします。

Gemfile

File: Gemfile

1
2
3
4
5
group :development, :test do
  gem 'rspec-rails', '~> 3.2.1'
  gem 'database_cleaner'
  gem 'factory_girl_rails'
end

バンドルインストールします。

1
[rails_app]$ bundle install

インストールコマンド

Rspec のインストールには次のコマンドを実行します。

1
[rails_app]$ rails generate rspec:install

その結果、「spec/」ディレクトリーが作られ、設定用の次のファイルが追加されます。

  • .rspec
  • spec/spec_helper.rb
  • spec/rails_helper.rb

spec/rails_helper.rb

インストールしたgemを利用できるようにrequireし、下部のconfigureの中に追加記入します。

File: spec/rails_helper.rb

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
require 'factory_girl'
require 'database_cleaner'

RSpec.configure do |config|
  config.before(:suite) do
    DatabaseCleaner.strategy = :truncation
  end

  config.before(:each) do
    DatabaseCleaner.start
  end

  config.after(:each) do
    DatabaseCleaner.clean
  end

    ...

end

DatabaseCleanerは毎回テストを実行するたびにデータベースを初期化するようにしました。

モデル、ファクトリーの定義を作成

作成するのはユーザーの権限を表す「Role」ですが、モデルだけ作成します。

Roleモデルの作成

ここで実行するコマンドを一覧しておきます。

  • rails generate model role role_name:string role_display_name:string
  • rake db:migrate
  • rspec spec

実行して確かめていきます。

1
[rails_app]$ rails generate model role role_name:string role_display_name:string

以下のように、モデルだけでなくRspecやFactoryGirlsで必要なファイルも作成されました。

1
2
3
4
5
6
7
   invoke  active_record
   create    db/migrate/20150530023253_create_roles.rb
   create    app/models/role.rb
   invoke    rspec
   create      spec/models/role_spec.rb
   invoke      factory_girl
   create        spec/factories/roles.rb

できたファイルを確認してみましょう。

File: app/models/role.rb

1
2
class Role < ActiveRecord::Base
end

File: spec/models/role_spec.rb

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
require 'rails_helper'

RSpec.describe Role, type: :model do
  pending "add some examples to (or delete) #{__FILE__}"
end
```ruby

File: spec/factories/roles.rb
{: .filename}
```ruby
FactoryGirl.define do
  factory :role do
    role_name "MyString"
role_display_name "MyString"
  end

end

rake db:migrateでデータベースを初期化します。

1
2
3
4
5
[rails_app]$ rake db:migrate
== 20150530023253 CreateRoles: migrating ======================================
-- create_table(:roles)
   -> 0.0007s
== 20150530023253 CreateRoles: migrated (0.0007s) =============================

この状態でRspecを実行してみます。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
[rails_app]$ rspec spec --format doc

Role
  add some examples to (or delete) /path/to/rails_app/spec/models/role_spec.rb (PENDING: Not yet implemented)

Pending: (Failures listed here are expected and do not affect your suite's status)

  1) Role add some examples to (or delete) /path/to/rails_app/spec/models/role_spec.rb
     # Not yet implemented
     # ./spec/models/role_spec.rb:4


Finished in 0.02596 seconds (files took 1.39 seconds to load)
1 example, 0 failures, 1 pending

role_spec.rbのpendingの行が実行、表示されています。後ほどこのファイルを修正変更していきます。

ファクトリーの定義

ここではFactoryGirlsで管理者権限と一般ユーザー権限を作成できるように spec/factories/roles.rb を編集します。レコードは一つずつできればよいのでfind_or_create_byを使っています。

File: spec/factories/roles.rb

1
2
3
4
5
6
7
8
9
10
11
12
13
14
FactoryGirl.define do

  factory :role_admin, class: Role do |r|
    r.role_name "admin"
    r.role_display_name "管理者"
    r.initialize_with { Role.find_or_create_by(role_name: role_name) }
  end

  factory :role_user, class: Role do |r|
    r.role_name "general_user"
    r.role_display_name "一般ユーザー"
    r.initialize_with { Role.find_or_create_by(role_name: role_name) }
  end
end

Roleモデルのテスト

仕様を決める

では、spec/models/role_spec.rb の編集を始めます。まずユーザー権限の仕様を決めていきましょう。

File: spec/models/role_spec.rb

1
2
3
4
5
6
7
8
9
10
11
require 'rails_helper'

RSpec.describe Role, type: :model do

  context "権限" do
    it "管理者権限がある。"
    it "一般ユーザー権限がある。"
    it "各権限は、データベースに1つずつしか作られない。"
  end

end

ブロックを付けずにitだけで仕様を記述すると見やすいですね。

ではRspecを実行してみます。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
[rails_app]$ rspec spec --format doc

Role
  権限
    管理者権限がある。 (PENDING: Not yet implemented)
    一般ユーザー権限がある。 (PENDING: Not yet implemented)
    各権限は、データベースに1つずつしか作られない。 (PENDING: Not yet implemented)

Pending: (Failures listed here are expected and do not affect your suite's status)

  1) Role 権限 管理者権限がある。
     # Not yet implemented
     # ./spec/models/role_spec.rb:6

  2) Role 権限 一般ユーザー権限がある。
     # Not yet implemented
     # ./spec/models/role_spec.rb:7

  3) Role 権限 各権限は、データベースに1つずつしか作られない。
     # Not yet implemented
     # ./spec/models/role_spec.rb:8


Finished in 0.02748 seconds (files took 1.4 seconds to load)
3 examples, 0 failures, 3 pending

このようにブロックなしでitを使うとペンディング扱いとなります。3個のテストがあり、失敗が0個でペンディングが3個と表示されています。

テストを実装する

管理者権限を作成し、データベースに正しく登録されたことを確認するテストを作ります。

  1. FactoryGirls 先ほど定義したファクトリーのうちファクトリー名が「:role_admin」の権限を作るには

    1
    
    FactoryGirl.create(:role_admin)
    

    のようにcreateメソッドを使うことでインスタンスを作成すると同時にデータベースへも登録されます。インスタンスだけ作成しデータベースへ登録しない時には、buildメソッドを使います。

    1
    
    FactoryGirl.build(:role_admin)
    
  2. Rspecのexpectメソッド 登録された値が、期待している値と等しいことをテストするには、

    1
    
    expect(受け取った値).to eq(期待する値)
    

    のように記述し、その否定のときには.to_not.not_toメソッドを使います。

    1
    
    expect(受け取った値).not_to eq(受け取ってはいけない値)
    

    と記述します(.to_notでもよい)。また、eqの部分は「マッチャー(matcher)」といい、be_truthybe_falseyのようないろいろなマッチャーがあります(今回はマッチャーについてはふれません)。

File: spec/models/role_spec.rb

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
require 'rails_helper'

RSpec.describe Role, type: :model do

  context "権限" do
    it "管理者権限がある。" do
      role_admin = FactoryGirl.create(:role_admin)
      role = Role.all

      expect(role.size).to eq(1)
      expect(role[0].role_name).to eq("admin")
      expect(role[0].role_display_name).to eq("管理者")
      expect(role[0]).to eq(role_admin)
    end
    it "一般ユーザー権限がある。"
    it "各権限は、データベースに1つずつしか作られない。"
  end

end

テスト事項は

  • Roleテーブルに登録されているのは1件である
  • 登録された「role_name」は「admin」である
  • 登録された「role_display_name」は「管理者」である

としました。ついでに登録したインスタンスと取得したActiveRecordが等しいこともテストしています。

rspecを実行します。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
[rails_app]$ rspec spec --format doc

Role
  権限
    管理者権限がある。
    一般ユーザー権限がある。 (PENDING: Not yet implemented)
    各権限は、データベースに1つずつしか作られない。 (PENDING: Not yet implemented)

Pending: (Failures listed here are expected and do not affect your suite's status)

  1) Role 権限 一般ユーザー権限がある。
     # Not yet implemented
     # ./spec/models/role_spec.rb:17

  2) Role 権限 各権限は、データベースに1つずつしか作られない。
     # Not yet implemented
     # ./spec/models/role_spec.rb:18


Finished in 0.04412 seconds (files took 1.44 seconds to load)
3 examples, 0 failures, 2 pending

無事、作成したテストは成功しました。

端末では、成功したテストは緑色にカラー表示され、失敗した時には赤色で表示されます。3個のテストのうち失敗は0個、2個がペンディングと表示されています。

テストを完成させ実行します。

File: spec/models/role_spec.rb

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
require 'rails_helper'

RSpec.describe Role, type: :model do

  context "権限" do
    it "管理者権限がある。" do
      role_admin = FactoryGirl.create(:role_admin)
      role = Role.all

      expect(role.size).to eq(1)
      expect(role[0].role_name).to eq("admin")
      expect(role[0].role_display_name).to eq("管理者")
      expect(role[0]).to eq(role_admin)
    end

    it "一般ユーザー権限がある。" do
      role_user = FactoryGirl.create(:role_user)
      role = Role.all

      expect(role.size).to eq(1)
      expect(role[0].role_name).to eq("general_user")
      expect(role[0].role_display_name).to eq("一般ユーザー")
      expect(role[0]).to eq(role_user)
    end

    it "各権限は、データベースに1つずつしか作られない。" do
      role_admin = FactoryGirl.create(:role_admin)
      role_user = FactoryGirl.create(:role_user)
      role = Role.all

      expect(role.size).to eq(2)

      FactoryGirl.create(:role_admin)
      FactoryGirl.create(:role_user)
      role.reload

      expect(role.size).to eq(2)
      expect(role[0]).to eq(role_admin)
      expect(role[1]).to eq(role_user)
      expect(role[2]).to eq(nil)

    end
  end

end

結果です。

1
2
3
4
5
6
7
8
9
10
11
[rails_app]$ rspec spec --format doc

Role
  権限
    管理者権限がある。
    一般ユーザー権限がある。
    各権限は、データベースに1つずつしか作られない。

Finished in 0.09157 seconds (files took 1.38 seconds to load)
3 examples, 0 failures

すべて成功し緑色になりました。

今回はテストの基本まででした。

次回にもう一度モデルのテストをより実践的に行います。

シェア
#内容発言者

rubyXL - Excelファイルの読み込み

Rspecでモデルのテスト

坂井和郎