Testing simple STI with FactoryGirl
Asked Answered
R

1

32

I have got a class, that is the base of some other classes that specializes the behavior:

class Task < ActiveRecord::Base
  attr_accessible :type, :name, :command
  validates_presence_of :type, :name, :command

  # some methods I would like to test

end

The class CounterTask inherits from Task

class CounterTask < Task 
end

This all works fine until I am trying to test the base class, since it must have a type.

FactoryGirl.define do
  factory :task do
    sequence(:name) { |n| "name_#{n}" }
    sequence(:command) { |n|  "command_#{n}" }
  end
end

How would you test the basic functionality of the superclass?

Ruggles answered 20/8, 2013 at 9:53 Comment(2)
Shouldn't your test be written so that it tests the functionality, rather than the implementation? In this case that would mean you would test whether CounterTask has the attributes and other things it gets from Task. If you change your implementation, for example not using STI anymore. Your test could still succeed if your CounterTask keeps the same behaviour.Murtha
That is a good point. I just thought I will save some duplications in the test if I first test the base functionality and then the child classes... Perhaps this might be the solution to my problem.Ruggles
T
73

You can declare the definitions of factories as follow:

FactoryGirl.define do
  factory :task, class: 'Task' do
    shop
    currency
    value 10
  end

  factory :counter_task, parent: :task, class: 'CounterTask' do
  end
end

And now you can test base class isolated from its own factory and the same for each inherited class.

Taxpayer answered 20/11, 2013 at 16:15 Comment(2)
I only needed to pass the class option to the child factory to make this work: factory :counter_task, class: 'CounterTask' do (no class option was necessary for the parent factory either).Spearwort
@Spearwort Omitting the class: 'Task' also works for me, but, parent: :task does seem to be significant if you want the properties defined in the task block to be defined when using counter_task. So, with parent: :task, build(:counter_task).value == 10. If you don't set the parent, build(:counter_task).value == nil.Regelate

© 2022 - 2024 — McMap. All rights reserved.