RubyMineでRailsをテスト駆動開発(Rspec)してみる(2)

[前の記事からの続きです](http://qiita.com/items/772fb58296beb747e1bd)

| Component       | version      |
|:----------------|-------------:|
| RubyMine        | 5.0(Windows) |
| Rails           | 3.2.12       |
| Rspec           | 2.13.0       |
| FactoryGirl     | 4.2.0        |
| Faker           | 1.1.2        |
| DatabaseCleaner | 0.9.1        |

## 1st Red

1. テストを書く

```ruby:spec/models/contact_spec.rb
 it "has a valid factory" do
    expect(FactoryGirl.build(:contact)).to be_valid
  end
```

2. Run > Run > spec

テストが走り、失敗する

3. Toggle auto-test

1. コードを書く

```ruby:spec/factories/contacts.rb
FactoryGirl.define do
  factory :contact do
    firstname "Tatsuro"
    lastname "Ueda"
    sequence(:email) { |n| "weed#{n}@yahoo.co.jp"}
  end
end
```

1. 自動的にテストが走り、合格する

1. テストをFactoryGirl仕様に修正する

```ruby:spec/models/contacts_spec.rb
  it "is valid with a firstname and lastname" do
    contact = FactoryGirl.build(
        firstname: 'Tatsuro',
        lastname: 'Tatsuro',
        email: 'weed_7777@yahoo.co.jp'
    )
    expect(contact).to be_valid
  end

  it "is invalid without a firstname" do
    #expect(Contact.new(firstname: nil)).to have(1).errors_on(:firstname)
    contact = FactoryGirl.build(:contact, firstname: nil)
    expect(contact).to have(1).errors_on(:firstname)
  end

  it "is invalid without a lastname" do
    #expect(Contact.new(lastname: nil)).to have(1).errors_on(:lastname)
    contact = FactoryGirl.build(:contact, lastname: nil)
    expect(contact).to have(1).errors_on(:lastname)
  end

  it "is invalid with a duplicate email address" do
    FactoryGirl.create(:contact, email: 'weed_7777@yahoo.co.jp')
    contact = FactoryGirl.build(:contact, email: 'weed_7777@yahoo.co.jp')
    expect(contact).to have(1).errors_on(:email)
  end

  describe "#name" do
    it "returns a contact's full name as a string" do
      contact = FactoryGirl.build(:contact,
          firstname: "Tatsuro", lastname: "Ueda"
      )
      expect(contact.name).to eq 'Tatsuro Ueda'
    end
  end
```

1. 自動的にテストが走り、合格する

1. 「FactoryGirl」を省略可能にする

```ruby:spec/spec_helper.rb
  config.include FactoryGirl::Syntax::Methods
```

1. テストを修正する

1. テストをFactoryGirl仕様に修正する

```ruby:spec/models/contacts_spec.rb
  it "has a valid factory" do
    expect(build(:contact)).to be_valid
  end

  it "is valid with a firstname and lastname" do
    contact = build(:contact,
                    firstname: 'Tatsuro',
                    lastname: 'Tatsuro',
                    email: 'weed_7777@yahoo.co.jp'
    )
    expect(contact).to be_valid
  end

  it "is invalid without a firstname" do
    contact = build(:contact, firstname: nil)
    expect(contact).to have(1).errors_on(:firstname)
  end

  it "is invalid without a lastname" do
    contact = build(:contact, lastname: nil)
    expect(contact).to have(1).errors_on(:lastname)
  end

  it "is invalid with a duplicate email address" do
    create(:contact, email: 'weed_7777@yahoo.co.jp')
    contact = build(:contact, email: 'weed_7777@yahoo.co.jp')
    expect(contact).to have(1).errors_on(:email)
  end

  describe "#name" do
    it "returns a contact's full name as a string" do
      contact = build(:contact,
                      firstname: "Tatsuro", lastname: "Ueda"
      )
      expect(contact.name).to eq 'Tatsuro Ueda'
    end
  end
```

1. 自動的にテストが走り、合格する

## 2nd Red

1. テストを書く

```ruby:spec/models/phones_spec.rb
  it "allows two contacts to share a phone number" do
    #contact = Contact.create(
    #    firstname: 'Tatsuro', lastname: 'Ueda', email: 'weed_7777@yahoo.co.jp'
    #)
    #contact.phones.create(
    #    phone_type: 'home',
    #    phone: '01-2345-6789'
    #)
    #other_contact = Contact.new
    #other_phone = other_contact.phones.build(
    #    phone_type: 'home',
    #    phone: '01-2345-6789'
    #)
    create(:phone, phone: "01-2345-6789")
    other_phone = build(:phone, phone: "01-2345-6789")
    expect(other_phone).to be_valid
  end
```

1. 自動的にテストが走り、コケる

1. コードを書く

```ruby:spec/factories/phones.rb
FactoryGirl.define do
  factory :phone do
    association :contact
    phone_type "home"
    phone "01-2345-6789"
  end
end
```

1. 自動的にテストが走り、合格する

## 3rd Red

1. テストを書く

```ruby:spec/models/phones_spec.rb
    create(:home_phone, phone: "01-2345-6789")
    other_phone = build(:home_phone, phone: "01-2345-6789")
    expect(other_phone).to be_valid
```

1. 自動的にテストが走り、コケる

1. コードを書く

```ruby:spec/factories/phones.rb
FactoryGirl.define do
  factory :phone do
    association :contact
    phone "01-2345-6789"

    factory :home_phone do
      phone_type "home"
    end

    factory :work_phone do
      phone_type "work"
    end

    factory :mobile_phone do
      phone_type "mobile"
    end
    
  end
end
```

1. 自動的にテストが走り、合格する

## Faker導入

1. コードを書く

```ruby:spec/factories/contacts.rb
FactoryGirl.define do
  factory :contact do
    firstname { Faker::Name.first_name }
    lastname { Faker::Name.last_name }
    email { Faker::Internet.email }
  end
end
```

```ruby:spec/factories/phones.rb
FactoryGirl.define do
  factory :phone do
    association :contact
    phone { Faker::PhoneNumber.phone_number }

...
```

1. 自動的にテストが走り、合格する

## 4th Red

1. テストを書く

```ruby:spec/models/contacts_spec.rb
  it "has three phone numbers" do
    expect(create(:contact).phones.count).to eq 3
  end
```

1. 自動的にテストが走り、コケる

1. コードを書く

```ruby:spec/factories/contacts.rb
FactoryGirl.define do
  factory :contact do
    firstname { Faker::Name.first_name }
    lastname { Faker::Name.last_name }
    email { Faker::Internet.email }

    after(:build) do |contact|
      [:home_phone, :work_phone, :mobile_phone].each do |phone|
        contact.phones << FactoryGirl.build(:phone,
            phone_type: phone, contact: contact)
      end
    end
  end
end
```

1. 自動的にテストが走り、合格する

-----
ブログやってます：[PAPA-tronix !](http://weed.cocolog-nifty.com/wzero3es/)