16

I'm trying to reuse a helper method in all my factories, however I cannot get it to work. Here's my setup:

Helper module (in spec/support/test_helpers.rb)

module Tests
  module Helpers
    # not guaranteed to be unique, useful for generating passwords
    def random_string(length = 20)
      chars = ['A'..'Z', 'a'..'z', '0'..'9'].map{|r|r.to_a}.flatten
      (0...length).map{ chars[rand(chars.size)] }.join
    end
  end
end

A factory (in spec/factories/users.rb)

FactoryGirl.define do
  factory :user do
    sequence(:username) { |n| "username-#{n}" }
    password random_string
    password_confirmation { |u| u.password }
  end
end

If I run my tests (with rake spec), I get the following error wherever I create a user with Factory(:user):

 Failure/Error: Factory(:user)
 ArgumentError:
   Not registered: random_string

What do I have to do to be able to use random_string in my factories?

I have tried the following:

  • using include Tests::Helpers at every level of my factory (before the define, between define and factory :user and inside factory :user)
  • in spec_helper.rb, I have the following already: config.include Tests::Helpers and it gives me access to random_string in my specs
  • simply requiring the file in my factory

I have also read the following links without success:

mbillard
  • 38,386
  • 18
  • 74
  • 98

3 Answers3

12

What about a mere:

module Tests
  module Helpers
    # not guaranteed to be unique, useful for generating passwords
    def self.random_string(length = 20)
      chars = ['A'..'Z', 'a'..'z', '0'..'9'].map{|r|r.to_a}.flatten
      (0...length).map{ chars[rand(chars.size)] }.join
    end
  end
end

Then:

FactoryGirl.define do
  factory :user do
    sequence(:username) { |n| "username-#{n}" }
    password Tests::Helpers.random_string
    password_confirmation { |u| u.password }
  end
end

Ok, got it :) Do as follows:

module FactoryGirl
  class DefinitionProxy
    def random_string
     #your code here
    end
  end
end
apneadiving
  • 114,565
  • 26
  • 219
  • 213
  • It works like that but I was hoping I would not have to write the whole namespace. I'll keep the question open in case someone finds a better way. – mbillard Oct 26 '11 at 19:40
  • It works, though I ended leaving my helper module as it is (with an instance method though) and including that module inside the `DefinitionProxy` class. Thanks a lot! – mbillard Oct 26 '11 at 21:02
  • 1
    Important to note: my `rand` method did not work as is and I had to replace it with `Kernel.rand` due to some conflict with FactoryGirl. – mbillard Oct 26 '11 at 21:12
7

apneadiving's answer did not work for me. I had to do the following:

# /spec/support/factory_helpers.rb
module FactoryHelpers
  def my_helper_method
    # ...
  end
end

FactoryGirl::Proxy.send(:include, FactoryHelpers)

Then you can use it as follows:

FactoryGirl.define do
  factory :post do
    title { my_helper_method }
  end
end
cuvius
  • 383
  • 1
  • 4
  • Looks much simpler, I'll try it when I have time. – mbillard Nov 25 '11 at 16:58
  • 10
    FG v4 doesn't use ::Proxy anymore - fwiw, you get the same effect by replacing `FactoryGirl::Proxy.send` in @cuvius answer with `FactoryGirl::SyntaxRunner.send` But note that the gem's developer is [thinking on a proper solution within the gem itself](https://github.com/thoughtbot/factory_girl/issues/564), so keep track of those developments as well if you're doing this. – sameers Dec 05 '13 at 01:03
4

I tested other answers yesterday (24.04.2012) and... none of them actually works.

Looks like Factory Girl gem (v3.2.0) have changed a lot.

But I figured out a quick solution:

# factories.rb
module FactoryMacros
  def self.create_file(path)
    file = File.new(path)
    file.rewind
    return ActionDispatch::Http::UploadedFile.new(:tempfile => file,
                                            :filename => File.basename(file))
  end
end
# also factories.rb
FactoryGirl.define do

  factory :thing do |t|
    t.file { FactoryMacros::create_file("path-to-file")
  end
end
nothing-special-here
  • 11,230
  • 13
  • 64
  • 94