RailsチュートリアルのテストをRSpecで実施【 Relationshipモデル 単体テスト編 3/3】

<!--
# RailsチュートリアルのテストをRSpecでやってみる Relationshipモデル 単体テスト編 3/3
-->

## Relationshipモデル

### 環境
[Userモデル 単体テスト編 1/3](https://qiita.com/shu130/items/57233462258d42566f18) に記載

#### フォルダ、使用ファイル

種類  |  ファイル名
:--|:--
スペック  |  spec/models/relationship_spec.rb
ファクトリ（ユーザ）  |  spec/support/factories/users.rb


### アウトライン作成

- subjectの定義、その有効性の確認
- 属性やメソッドの応答(respond_to)
- メソッドの検証（follow/followedメソッド）
  - Userモデルとの belongs_to の関連付けが正しいこと

```ruby:relationship_spec.rb
# spec/models/relationship_spec.rb
RSpec.describe Relationship, type: :model do

  let(:user) { create(:user) }             # => フォローしているユーザ
  let(:other_user) { create(:other_user) } # => フォローされているユーザ
  let(:active) { user.active_relationships.build(followed_id: other_user.id) }
  subject { active }

  # リレーションシップが有効であること
  it { should be_valid }

  # follow/followedメソッド
  describe "follower/followed methods"
    # followメソッドは、フォローしているユーザを返すこと
    it "follower method return following-user"
    # followerメソッドは、フォローされているユーザを返すこと
    it "followed method return followed-user"

  # validations
  describe "validations" do
    # 存在性 presence
    describe "presence" do
      it "follower_id should not be empty"
      it "followed_id should not be empty"
    end
  end
end
```

#### コンソールで確認

- `active.follower` が `user` を返すこと
- `active.followed` が `other_user` を返すこと

  ```test
  （抜粋）
  $ rails console test --sandbox

  [1] pry(main)>
  [2] pry(main)> user = FactoryBot.create(:user)
   id: 5,
   name: "Example user",
   email: "user@example.com",
   created_at: Sun, 05 Aug 2018 09:00:59 UTC +00:00,
   updated_at: Sun, 05 Aug 2018 09:00:59 UTC +00:00,

   （省略）

  [3] pry(main)>
  [4] pry(main)> other_user = FactoryBot.create(:other_user)
   id: 6,
   name: "Lina Kuvalis",
   email: "shadtowne@torp.net",
   created_at: Sun, 05 Aug 2018 09:01:21 UTC +00:00,
   updated_at: Sun, 05 Aug 2018 09:01:21 UTC +00:00,

   （省略）

  [6] pry(main)> active = user.active_relationships.build(followed_id: other_user.id)
  => #<Relationship:0x007f871e4ab120 id: nil, follower_id: 5, followed_id: 6, created_at: nil, updated_at: nil>

  [8] pry(main)> active.follower
    User Load (1.6ms)  SELECT  "users".* FROM "users" WHERE "users"."id" = ? LIMIT ?  [["id", 5], ["LIMIT", 1]]
  => #<User:0x007f871d592f58
   id: 5,
   name: "Example user",
   email: "user@example.com",

   （省略）

  [9] pry(main)>
  [11] pry(main)>
  [12] pry(main)> active.followed
    User Load (0.1ms)  SELECT  "users".* FROM "users" WHERE "users"."id" = ? LIMIT ?  [["id", 6], ["LIMIT", 1]]
  => #<User:0x007f871d3e30e0
   id: 6,
   name: "Lina Kuvalis",
   email: "shadtowne@torp.net",

   （省略）

  ```

### スペック作成

```ruby:relationship_spec.rb
# spec/models/relationship_spec.rb

require 'rails_helper'

RSpec.describe Relationship, type: :model do

  let(:user) { create(:user) }             # => フォローしているユーザ
  let(:other_user) { create(:other_user) } # => フォローされているユーザ
  let(:active) { user.active_relationships.build(followed_id: other_user.id) }
  subject { active }

  # リレーションシップが有効であること
  it { should be_valid }

  # follow/followedメソッド
  describe "follower/followed methods" do
    it { should respond_to(:follower) }
    it { should respond_to(:followed) }
    # followメソッドは、フォローしているユーザを返すこと
    it "follower method return following-user" do
      expect(active.follower). to eq user
    end
    # followerメソッドは、フォローされているユーザを返すこと
    it "followed method return followed-user" do
      expect(active.followed). to eq other_user
    end
    # or
    # its(:follower) { should eq user }
    # its(:followed) { should eq other_user }
  end

  # validations
  describe "validations" do
    # 存在性 presence
    describe "presence" do
      it { is_expected.to validate_presence_of :followed_id }
      it { is_expected.to validate_presence_of :follower_id }
    end
  end
end
```

### 実行結果

```test
$bin/rspec spec/models/relationship_spec.rb

Relationship
  should be valid
  follower/followed methods
    should respond to #follower
    should respond to #followed
    follower method return following-user
    followed method return followed-user
  validations
    presence
      should validate that :followed_id cannot be empty/falsy
      should validate that :follower_id cannot be empty/falsy

Finished in 2.06 seconds (files took 2.06 seconds to load)
7 examples, 0 failures

```

--------------------------------

### 参考

- [Railsチュートリアル Rails4.0(第2版)](https://railstutorial.jp/chapters/modeling-users?version=4.0#top)

- [(書籍)leanpub - Everyday Rails - RSpecによるRailsテスト入門](https://leanpub.com/everydayrailsrspec-jp/)

--------------------------------


### 以上
#### 続く [フィーチャースペック編 users_index_spec 1/7](https://qiita.com/shu130/items/376615938e5956f44c06)