dennismonsewicz
dennismonsewicz

Reputation: 25552

Confusion with setting up FactoryGirl and associations with Rspec

I am fairly new to learning TDD and what all goes into being successful at it.

Here are my Factories (so far):

FactoryGirl.define do
  sequence(:email) do |n|
    "user#{n}@example.com"
  end

  factory :user do
    email
    first_name Faker::Name.first_name
    last_name Faker::Name.last_name
    password "password"
    password_confirmation "password"
    agreed_to_age_requirements true
    username "testing123"
    state "AL"
    city_id 201
    school_id 20935
    handedness "Left"

    subscriptions {[create(:subscription)]}
    roles {[create(:role)]}
  end

  factory :athlete, class: "Athlete", parent: :user do
    type "Athlete"
    recruit_year "2016"
  end
end

FactoryGirl.define do
  factory :subscription do
    trial_expiry 30.days.from_now
    active true

    account_type {create(:account_type, name: "Free", price: 0)}
  end
end

FactoryGirl.define do
  factory :role do
    name "Subscription Admin"
  end
end

Here is my Spec file:

require 'spec_helper'

describe School do

  describe "associations" do
    it { should belong_to(:city) }
    it { should have_many(:users) }
    it { should have_many(:athletes) }
  end

  describe "validations" do
    it { should validate_presence_of(:name) }
    it { should validate_presence_of(:state) }
  end

  describe "scopes" do
    before(:each) do
      @school = create(:school, city_id: 1)
    end

    it "returns a school with the given city id" do
      School.in_city(1).should include(@school)
    end

    it "excludes schools that are not in the given city" do
      School.in_city(2).should_not include(@school)
    end
  end

  describe "instance methods" do
    let(:other_school) { create(:school, name: "Football High", state: "GA") }
    let(:athlete) { create(:athlete, school: other_school) }

    describe "#generate_custom_slug" do
      it "should return parameterized model" do
        other_school.generate_custom_slug.should eq("#{other_school.state.downcase} #{other_school.name.parameterize}")
      end
    end

    describe "#all_athletes" do

      context "when no parameters are passed in" do
        it "should return an array of athletes that belong to school" do
          other_school.all_athletes.should include(athlete)
        end
      end

      context "when given a sport name" do
        it "should return an array of athletes with the given sport name that belong to the school" do)
          other_school.all_athletes("football").should include(athlete)
        end
      end
    end
  end
end

Where I am "stuck" at is testing my last context. A User has many sports through user_sports and when you visit /schools/1/football a list of all athletes that belong to that school that play football should be returned by the all_athletes instance method. I am just confused on how to set that up with FactoryGirl

For reference, here is my School model:

class School < ActiveRecord::Base
  extend FriendlyId
  friendly_id :generate_custom_slug, use: :slugged

  belongs_to :city
  has_many :users
  has_many :athletes

  validates_presence_of :name, :state

  default_scope order: 'name ASC'

  scope :in_city, ->(city_id) { where city_id: city_id }

  def titleized_name
    self.name.titleize
  end

  def generate_custom_slug
    # only generate a slug if the state and name are present
    # if they aren't present, validations fail
    "#{state.downcase} #{name.downcase.parameterize}" if state.present? && name.present?
  end

  def all_athletes(sport_name = nil, recruit_year = nil)
    return athletes if sport_name.nil? && recruit_year.nil?
    results = athletes.select { |athlete| !(athlete.sports & Sport.by_name_label(sport_name)).empty? } unless sport_name.nil?
    results = results.select { |athlete| athlete.recruit_year.eql?(recruit_year.to_i) } unless recruit_year.nil?

    results
  end
end

Upvotes: 0

Views: 217

Answers (1)

Lukas Oberhuber
Lukas Oberhuber

Reputation: 1064

I'd say in this instance, unless athletes and schools are hard to set up, you could probably avoid using FactoryGirl at all. Create a school, and add an athlete (or athletes) in each test. If you want it all to be more complex, then go to FactoryGirl later.

Upvotes: 2

Related Questions