あれやこれやしたRailsのモデル用Specファイル その2


```ruby

# -*- coding: utf-8 -*-
require 'spec_helper'

describe Team do

  let(:valid_model) { FactoryGirl.build(:team_base) }
  let(:created_model) { FactoryGirl.create(:team_base) }

  # idで抽出できることを確認する
  shared_examples_for :can_find_by_team_id do |id|
    it {->{Team.find(id)}.should_not raise_error(ActiveRecord::RecordNotFound)}
  end

  # idで抽出できないことを確認する
  shared_examples_for :can_not_find_by_team_id do |id|
    it {->{Team.find(id)}.should raise_error(ActiveRecord::RecordNotFound)}
  end

  # 属性の値を変更したらinvalid?がfalseからtrueになることを確認する
  shared_examples_for :to_invalid_after_attr_change do |name, test_values|
    describe name do
      test_values.each do |label, value|
        context "set '#{value}'(#{label.to_s})" do
          subject { target_model }
          it { ->{ subject[name] = value}.should change(subject, :invalid?).from(false).to(true)}
        end
      end
    end
  end

  # インスタンス生成直後は保存できない
  context 'when new' do
    subject{ Team.new }
    its(:valid?) { should_not be_true }
    its(:save) { should be_false}
  end

  # 以降で使用する保存可能なモデルが本当に保存できるか確認
  describe 'valid model' do
    subject { valid_model }
    its(:valid?) { should be_true }
    its(:save) { should be_true }
  end

  context 'after save' do
    # 保存したら1件増える
    it { ->{ created_model }.should change(Team, :count).by(1) }
    # 抽出できること
    it_behaves_like :can_find_by_team_id, FactoryGirl.create(:team_base).id
  end

  context 'after delete' do
    # let!はbefore(:each)みたいに各サンプルの前に実行される
    let!(:target) { FactoryGirl.create(:team_base) }

    # 削除されたら1件減る
    it { ->{ target.delete }.should change(Team, :count).by(-1) }
    # 抽出できないこと
    it_behaves_like :can_not_find_by_team_id, FactoryGirl.create(:team_base).delete.id
  end

  context 'after destroy' do
    let!(:target) { FactoryGirl.create(:team_base, member_count: 10) }

    it {->{ target.destroy }.should change(Team, :count).by(-1) }
    it_behaves_like :can_not_find_by_team_id, FactoryGirl.create(:team_base).destroy.id
  end

  # validatesをまとめて確認
  describe 'attributes' do

    test_values = {empty: '', length_over: 'あいうえおあいうえおあいうえおあいうえおあ'}

    it_behaves_like :to_invalid_after_attr_change , 'name', test_values do
      let(:target_model) { valid_model }
    end

  end

  describe 'members attribute' do

    context 'can add new member' do
      subject { created_model }
      let!(:new_member) { FactoryGirl.create(:player) }
      it { ->{ subject.add_member(new_member) }.should change(subject.members, :count).by(1) }
    end

    context 'can remove a member' do
      subject { created_model }
      let!(:new_member) { FactoryGirl.create(:player) }
      let!(:member_add) { subject.add_member(new_member); subject }
      it { ->{ member_add.remove_member(new_member) }.should change(subject.members, :count).by(-1) }
    end

    context 'after destroy' do
      let!(:target) { FactoryGirl.create(:team_base, member_count: 10) }
      let!(:members_count) { target.members.count }
      it {->{ target.destroy }.should change(target.members, :count).from(members_count).to(0)}
    end

  end

  describe 'players method' do
    context 'add 5 players' do
      before do
        @team = FactoryGirl.create(:team_base, add_manager: false)
        players = FactoryGirl.create_list(:player, 5)
        players.each { |p| @team.add_member(p) }
      end

      subject { @team }
      let!(:players_count) { subject.members.find_all_by_member_type(Member::MemberTypes[:player]).count }
      its('players.count') { should == players_count}
    end
  end

  describe 'managers method' do
    context 'add 5 managers' do
      before do
        @team = FactoryGirl.create(:team_base, add_manager: false)
        managers = FactoryGirl.create_list(:manager, 5)
        managers.each { |p| @team.add_member(p) }
      end

      subject { @team }
      let!(:managers_count) { subject.members.find_all_by_member_type(Member::MemberTypes[:manager]).count }
      its('managers.count') { should == managers_count }
    end
  end
end
```