[Unit Testing for Zombie] 06. Using Factory

FACTORIES

Convert the zombies fixture to a Factory Girl Factory called :zombie.

test/fixture/zombies.yml

zombie:
  name: 'Sally'
  graveyard: 'Valley Dim'

Answer:

test/factories/zombies.rb

FactoryGirl.define do
  factory :zombie do
   name 'Sally'
   graveyard 'Valley Dim'
  end
end

 

Why using factory instead of fixture?

 

COMPLEX FACTORIES

Use a nested Factory Girl definition to create zombie factories named :sally and :moe, using the data from the fixtures below.

test/fixtures/zombies.yml

ash:
  name: 'Ash'
  graveyard: 'Petrosville'
 
sally:
  name: 'Sally'
  graveyard: 'Valley Dim'
 
moe:
  name: 'Moe'
  graveyard: 'Petrosville'

Answer:

test/factories/zombies.rb

FactoryGirl.define do
  factory :zombie do
    name 'Ash'
    graveyard 'Petrosville'

    # Add sally and moe here
    factory :sally do
      name 'Sally'
      graveyard 'Valley Dim'
    end
    
    factory :moe do
      name 'Moe'
    end
  end
end

 

How to create a factory?

What's good in factory?

We can use nested factory to create new factory and reused common part.

 

UNIQUE ATTRIBUTES

Refactor the zombie factory using a sequence so that we get a unique name and graveyardeverytime we create a new zombie.

FactoryGirl.define do
  factory :zombie do
    sequence(:name) {|i| "Ash#{i}" }
    sequence(:graveyard) { |j| "Petrosville Cemetary#{j}" }
  end
end

 

Why using sequence?

Every time using a Factory, it equals to :

FactoryGirl.create(:zombie) //create new zombie instance and save into db

But if the data should be uniqueness, then it will cause some problem like: ActiveRecord: RecordInvalid.

Then we can use sequence to solve this problem.

 

ASSOCIATIONS

Create a tweet factory with a zombie association, don't forget to set a tweet status.

FactoryGirl.define do
  factory :zombie do
    name 'Sally'
    graveyard 'Valley Dim'
  end
end

Answer:

FactoryGirl.define do
  factory :tweet do
    status "Eat a brain"
    association :zombie
  end
end

 

What about data relationship?

 

USING FACTORIES

Using factories write a test to verify that a tweet is invalid without a status. Be sure tobuild the Tweet, rather than create it.

FactoryGirl.define do
  factory :tweet do
    association :zombie
    status "Need brain factory."
  end
end

Answer:

class TweetTest < ActiveSupport::TestCase
  test "A tweet requires a status" do
    tweet = Factory.build(:tweet, status: nil)
    assert !tweet.valid?, "Status is not being validated"
  end
end

 

USING FACTORIES II

Create a tweet using a factory. Then, using Capybara, go to the tweets_url, click on thetweet.status link. Finally, assert that the tweet's show page contains the@tweet.zombie.name in its h3. Use Capybara's within and has_content? methods.

//index.html

<ul class="tweets">
  <li><%= link_to @tweet.status, tweets_url(@tweet) %></li>
</ul>
//show.html

<div id='<%="tweet_#{@tweet.id}"%>'>
  <h3><%= @tweet.zombie.name %></h3>
  <p><%= @tweet.status %></p>
</div>

test/factories/tweets.rb

FactoryGirl.define do
  factory :tweet do
    association :zombie
    status "Need brain factory."
  end
end

factories/zombies.rb

FactoryGirl.define do
  factory :zombie do
    name "Ash"
    graveyard "Factory Hills Cemetary"
  end
end

Answer:

class TweetTest < ActionDispatch::IntegrationTest
  test "tweet page has zombie link" do 
    tweet = Factory(:tweet)
    visit tweets_url
    click_link tweet.status
    
    within("h3") do
      assert has_content? (tweet.zombie.name)
    end
  end
end

 

posted @ 2014-11-12 22:15  Zhentiw  阅读(503)  评论(0编辑  收藏  举报