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?

Mark
  • 7,507
  • 12
  • 52
  • 88
  • 3
    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. – Arjan Aug 20 '13 at 10:01
  • 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. – Mark Aug 20 '13 at 10:17

1 Answers1

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.

Corey Adler
  • 15,897
  • 18
  • 66
  • 80
emaxi
  • 1,799
  • 1
  • 16
  • 13
  • 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). – gabe Mar 25 '15 at 23:37
  • 1
    @gabe 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`. – LiamD Jul 20 '16 at 16:09