Module: ModelFactory::Legacy

Defined in:
lib/modelfactory/legacy.rb

Overview

ModelFactory Legacy API

Put something like this in your test helper:

require 'model_factory'

module Factory
  extend ModelFactory

  # a default block accepts a class and a hash of default values
  default Color, {
    :name => 'chartreuse'
  }

  default User, {
    :first_name => 'Harry',
    :last_name => 'Manchester',
    :favorite_color => default_color
  }

  # Add class methods to create whatever kind of objects you need for your tests
  def self.new_user_with_colorblindness
    new_user { :favorite_color => nil }
  end

end

Then in your tests you use Factory methods to instantiate your test objects:

# For most functional tests you can use create.
def test_something
  user = Factory.create_user
  user.friends << Factory.create_user(:first_name => 'Frank')
  assert user.likes_frank?
end

# For unit tests you use new.
def test_something_else
  user = Factory.new_user(:favorite_color => Factory.new_color(:name => 'blue'))
  assert user.likes_blue?
end

# Assertions should not depend on default data, but it can be useful to create
# factory methods that build objects with specific traits.
def test_yet_something_else
  user = Factory.new_user_with_colorblindness
  assert !user.likes_blue?
end

You can also specify types of models in your calls to defaults, but be careful. This can easily start to become a lot like fixtures:

module Factory
  extend ModelFactory

  default User, :joined {
    :first_name => 'Harry',
    :last_name => 'Manchester',
    :joined => true,
    :set_password => true,
  }

  default User, :unjoined {
    :first_name => 'Harry',
    :last_name => 'Manchester',
    :joined => false,
    :set_password => false,
  }
end

Then in your test:

def test_something
  user1 = Factory.create_joined_user(:first_name => 'Bill')
  user2 = Factory.create_unjoined_user(:first_name => 'Sandy')
  assert  user1.joined?
  assert !user2.joined?
end

Instance Method Summary collapse

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(missing_method, attributes = {}) ⇒ Object

Any class methods of the form “new_some_type(attrs)” or “create_some_type(attrs)” will be converted to “SomeType.new(attrs)” and “SomeType.create!(attrs)” respectively. These basically function as though you’d used the ‘default’ directive with empty defaults.



174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
# File 'lib/modelfactory/legacy.rb', line 174

def method_missing(missing_method, attributes = {})
  if missing_method.to_s.match(/^(new|create|default)_([a-z][\w_]+)$/)
    method, class_name = $1, $2
    class_type = class_name.camelize.constantize
    case method
    when 'create'
      create_instance(class_type, attributes)
    when 'new'
      new_instance(class_type, attributes)
    when 'default'
      default_closure(class_type, attributes)
    end
  else
    raise NoMethodError, "no such method '#{missing_method}'"
  end
end

Instance Method Details

#create_instance(class_type, attributes, defaults = {}) ⇒ Object

:nodoc:



117
118
119
120
121
122
123
124
# File 'lib/modelfactory/legacy.rb', line 117

def create_instance(class_type, attributes, defaults = {}) # :nodoc:
  attributes = instantiate_defaults(:create, defaults.merge(attributes))
  instance = class_type.create!(attributes)
  if update_protected_attributes(instance, attributes)
    instance.save
  end
  instance
end

#default(class_type, *default_args) ⇒ Object

When specifying defaults, you should only provide only enough data that the created instance is valid. If you want to include another factory object as a dependency use the special method default_* instead of create_* or new_*.



93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
# File 'lib/modelfactory/legacy.rb', line 93

def default(class_type, *default_args)
  defaults   = default_args.pop || {}
  prefix     = default_args.first
  class_name = class_type.name.demodulize.underscore
  class_name = "#{prefix}_#{class_name}" if prefix

  (class << self; self; end).module_eval do
    define_method "create_#{class_name}" do |*args|
      attributes = args.first || {}
      create_instance(class_type, attributes, defaults)
    end
  
    define_method "new_#{class_name}" do |*args|
      attributes = args.first || {}
      new_instance(class_type, attributes, defaults)
    end

    define_method "default_#{class_name}" do |*args|
      attributes = args.first || {}
      default_closure(class_type, attributes, defaults)
    end
  end
end

#default_closure(class_type, attributes, defaults = {}) ⇒ Object

:nodoc:



134
135
136
137
138
139
140
141
# File 'lib/modelfactory/legacy.rb', line 134

def default_closure(class_type, attributes, defaults = {}) # :nodoc:
  lambda do |create_or_new|
    case create_or_new
    when :new    ; new_instance(class_type, attributes, defaults)
    when :create ; create_instance(class_type, attributes, defaults)
    end
  end
end

#instantiate_defaults(create_or_new, attributes) ⇒ Object

:nodoc:



143
144
145
146
147
148
149
150
# File 'lib/modelfactory/legacy.rb', line 143

def instantiate_defaults(create_or_new, attributes) # :nodoc:
  attributes.each do |key, value|
    if value.is_a?(Proc)
      attributes[key] = value.arity == 0 ? value.call : value.call(create_or_new)
    end
  end
  attributes
end

#new_instance(class_type, attributes, defaults = {}) ⇒ Object

:nodoc:



126
127
128
129
130
131
132
# File 'lib/modelfactory/legacy.rb', line 126

def new_instance(class_type, attributes, defaults = {}) # :nodoc:
  attributes = instantiate_defaults(:new, defaults.merge(attributes))
  instance = class_type.new(attributes)
  instance.id = next_local_id
  update_protected_attributes(instance, attributes)
  instance
end

#next_local_idObject

:nodoc:



82
83
84
85
# File 'lib/modelfactory/legacy.rb', line 82

def next_local_id # :nodoc:
  @max_id ||= 0
  return @max_id += 1
end

#update_protected_attributes(instance, attributes) ⇒ Object

:nodoc:



152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
# File 'lib/modelfactory/legacy.rb', line 152

def update_protected_attributes(instance, attributes) # :nodoc:
  modified = false
  protected_attrs  = instance.class.protected_attributes
  protected_attrs  = protected_attrs.to_set if protected_attrs
  accessible_attrs = instance.class.accessible_attributes
  accessible_attrs = accessible_attrs.to_set if accessible_attrs

  if protected_attrs or accessible_attrs
    attributes.each do |key, value|
      # Support symbols and strings.
      next if protected_attrs  and (not protected_attrs.include?(key) or protected_attrs.include?(key.to_s))
      next if accessible_attrs and (accessible_attrs.include?(key) or accessible_attrs.include?(key.to_s))
      modified = true
      instance.send("#{key}=", value)
    end
  end
  return modified
end