thoughtbot / factory_bot Goto Github PK
View Code? Open in Web Editor NEWA library for setting up Ruby objects as test data.
Home Page: https://thoughtbot.com
License: MIT License
A library for setting up Ruby objects as test data.
Home Page: https://thoughtbot.com
License: MIT License
I've created a branch which makes the stubbing strategy more friendly for non-AR classes.
http://github.com/sandro/factory_girl/tree/stub_for_non_ar_objects
The main issue is that the stubbing proxy calls #new which won't work if #initialize takes requires arguments. The fix is to fall back to #allocate when #new fails.
Hi,
Just sent a pull request for a small patch that keeps a list of generated objects in a cache so they can be forensically analysed on broken test runs.
I'm not sure if this is a valuable feature or not for the community, but please, review the patch ( http://github.com/leehambley/factory_girl/commit/feb72764c84fa76b31757f0c67f50f88262e3932 ) and I'd love some feedbac either way.
More info in the pull request that I sent, but that's not too important the code speaks for itself.
Factory girl doesn't work with classes where you override the initialize method and require params. This is common with "default" plugins like default_value_for. This patch fixes it by allowing you to set a constructor_args block that will retrieve the args that should be passed to the build class.
http://github.com/jeffrafter/factory_girl/commit/3cb82f8a7311527246d3f9c4c67d6816b26c1682
I didn't realize that rake gemspec would rev the version, so I accidentally revved the gemspec version in this commit. Let me know if that needs adjusting.
Reported by George Ogata
Hi,
I’ve found h-lame’s after_{build,create} callbacks a very useful addition to factory_girl. Only thing is his changes are on an old commit. I’ve merged his patch with your head in my fork [1], and was hoping you’d merge it in.
We use factory_girl to populate our demo environments with representative test data (users, accounts, etc.). Often we like to
rake db:drop
rake db:setup
then call our custom task to use our factories.
Problem is: after a db:drop there are no tables in the database, which prevents Factory Girl from loading the factory definitions -- and prevents us from pretty much doing anything. Quick workaround was to comment out the requirement for the factory_girl gem in environment.rb -- but I'd think it might be better to stop factory_girl from loading factory definitions when the db is blank,
What do you guys think?
Could you make it possible to allow to pass extra arguments to be used in the callbacks or in some other ways.
To be able to do something like this:
Factory.define :blog do |blog|
blog.name "Blah"
blog.after_create do |blog|
blog.posts += sample_posts
blog.save!
end
end
and then create it with something like this:
Factory.create(:blog, :sample_posts => [post1, post2])
Thanks.
Singleton factories are useful for creating unique instances, such as a fixed set of movie genres. The branch at http://github.com/roderickvd/factory_girl/tree/singletons adds the following syntax to do just that:
# Defines a new singleton Factory.define :comedy, :class => Genre, :singleton => true do |g| g.name 'Comedy' end
Because the singleton option is set on the factory, it works seamlessly for associations and all strategies.
Factory.define :building, :class => Building::Mothership do |m|
m.x 0
m.x_end { |r| r.x + r.instance_variable_get("@instance").class.property('width') }
end
It would be nice to just be able to
Factory.define :building, :class => Building::Mothership do |m|
m.x 0
m.x_end { |r, options| r.x + options[:class].property('width') }
end
I think I managed to make factory_girl work with Rails 2 (tested with 2.3.5) and Rails 3. There's just 1 failing test on Ruby 1.8.7 (it's on master branch as well) and 78 on Ruby 1.9.1, however I think that it's mainly caused by RR gem.
Here's my branch: http://github.com/szimek/factory_girl/tree/rails3
Reported by Eric Mill
#13 describes syntactic sugar for one-off sequences inside factory definitions. This request is to expand that, and allow for easy referencing of separately defined sequences.
Referencing a separately defined sequence by name:
Factory.define :user do |u| u.sequence :email, :user_email end Factory.sequence(:user_email {|n| "user#{n}@mail.com"}
Auto-referencing a separately defined sequence by using the same name:
Factory.define :user do |u| u.sequence :email end Factory.sequence(:email) {|n| "user#{n}@mail.com"}
And here's a crazier, but cooler idea at syntax, that assumes that a symbol passed as an attribute value refers to the name of a sequence:
Factory.define :user do |u| u.email :user_email end Factory.sequence(:user_email) {|n| "user#{n}@mail.com"}
The last example would eliminate the need for supporting either of the first two.
Factory.define :proposal do |p|
p.type "Session"
end
Boom! `type': wrong number of arguments (1 for 0) (ArgumentError)
Reported by Dmitry A. Ustalov
Hello.
I'm using both factory_girl and faker gems to simplify my application' testing, and when I'm defining my model's attributes by faker, they takes same values, check this: http://gist.github.com/168441
As result I have output like this:
#<Entity:0xb7df57c0 @email="[email protected]">
#<Entity:0xb7df5630 @email="[email protected]">
#<Entity:0xb7df5540 @email="[email protected]">
Reopening issue 12.
Ran into some trouble when trying to use factory sequences with spork + autospec—dozens of "Validation failed: Name has already been taken" errors. Changing Factory.find_definitions to use load instead of require takes care of the issue.
If anyone has a better suggestion, I'm open to it. If not, please consider merging this: http://github.com/jdhollis/factory_girl/commit/08fae46d01ad3faa7ecfc320e38f4696ac026041
The branch is here: http://github.com/jdhollis/factory_girl/tree/load-instead-of-require
Not sure if this is a bug or my misunderstanding of how factory_girl works...docs and lib/factory_girl.rb suggest that factories autoloaded from:
test/factories.rb
spec/factories.rb
test/factories/*.rb
spec/factories/*.rb
Comments and code in lib/factory_girl/factory.rb show "factories" should also be autoloaded.
Should
File.join(RAILS_ROOT, 'factories')
be in lib/factory_girl.rb or am I reading this wrong?
In lib/factory_girl.rb:
if defined? Rails.configuration
Rails.configuration.after_initialize do
Factory.definition_file_paths = [
File.join(RAILS_ROOT, 'test', 'factories'),
File.join(RAILS_ROOT, 'spec', 'factories')
]
Factory.find_definitions
end
else
Factory.find_definitions
end
In lib/factory_girl/factory.rb
class << self
attr_accessor :factories #:nodoc:
# An Array of strings specifying locations that should be searched for
# factory definitions. By default, factory_girl will attempt to require
# "factories," "test/factories," and "spec/factories." Only the first
# existing file will be loaded.
attr_accessor :definition_file_paths
end
self.factories = {}
self.definition_file_paths = %w(factories test/factories spec/factories)
Problem: a factory define that has a parent seems to be failing because the parent isn't loaded yet.
Example:
test/factories/person.rb Factory.define :person do |p| p.name 'Joe' end test/factories/person_with_extras.rb Factory.define :person_with_extras, :parent => :person do |p| p.age 21 end
Using the code above gives this error: No such factory: person.
Is it correct that a factory can have a parent like this, in a different file?
When I look in the gem factory.rb, it seems that the load order is inconsistent on line 276:
Dir[File.join(path, '*.rb')].each do |file|
I would expect at least for the files to be in alphabetic order:
- Dir[File.join(path, '*.rb')].each do |file| + Dir[File.join(path, '*.rb')].sort.each do |file|
Is there something obvious that I'm missing?
Or is it supposed to be this way?
Could the Thoughtbot team at least add the "sort" to the file list?
Much obliged,
Joel Parker Henderson
[email protected]
Currently I have to specify :default_strategy => :build for every factory.
Given these factories:
Factory.define :user do |u|
u.after_build do |user|
raise "after_build of :user"
end
end
Factory.define :admin_user, :parent => :user do |u|
u.admin = true
u.after_build do |user|
raise "after_build of admin_user"
end
end
And this code somewhere in a test:
user = Factory.create(:admin_user)
I would expect that I would get a raised error of "after_build of :user
" first, since it is the parent, and the children should be dependant on it's result. However, what I'm seeing is that "after_build of admin user
" is the first line raised, indicating that the callbacks for parent/child relationships are called in an improper order.
I'm doing a callback chain similar to this, where the child factory's after_build
callback does something that depends on it's parents after_build
having been run first - Is this a valid issue? Thanks :)
Hi,
Just to point out the need to add lib/factory_girl/attribute/callback.rb file to the one included into gemspec, after Nate patch.
Commit's here: http://github.com/ook/factory_girl/commit/b7c6fb724e8f569d2452d1a1de75178af583ac69
Reported by Erik
The method variable_name_to_class_name has code that translates, say, 'active_record/base' to ActiveRecord::Base. But when I tried to use this, I got a 'wrong constant name' error, because constant names can't contain colons.
You can just supply a :class option, but it would be easier not to. I'm planning to fix the code and document the shortcut.
Here's my fix: http://github.com/eostrom/factory_girl/tree/guess_classes_in_modules
Reported by Alex Rothenberg
When I have a model class defined within a module FactoryGirl was unable to find the class correctly because it was not traversing down the module hierarchy.
The fix along with a spec that fails before and passes after are at http://github.com/alexrothenberg/factory_girl/commits/factories_for_classes_with_modules_patch
My scenario is that I have a model defined in a module
module BlogModels class Comment < ActiveRecord::Base end end
and want to define a factory for it like this
Factory.define 'blog_models/comment' do |comment| end
It fails with this error
1) NameError in 'Factory a factory defined with a module name should load the class defined inside the module' wrong constant name GroupingOfModels::Comment /Users/alexrothenberg/ruby/github/factory_girl/spec/../lib/factory_girl/factory.rb:304:in `const_get' /Users/alexrothenberg/ruby/github/factory_girl/spec/../lib/factory_girl/factory.rb:304:in `class_for' /Users/alexrothenberg/ruby/github/factory_girl/spec/../lib/factory_girl/factory.rb:58:in `build_class' ./spec/factory_girl/factory_spec.rb:306:
Patching the class_for method in factory.rb to go down the module hierarchy as it loads the class fixes the problem.
I hope this is not too much information in the ticket but I thought it was better to err with too much rather than too little :)
Thanks
Alex
Ran into some trouble when trying to use factory sequences with spork + autospec—dozens of "Validation failed: Name has already been taken" errors. Changing Factory.find_definitions to use load instead of require takes care of the issue.
If anyone has a better suggestion, I'm open to it. If not, please consider merging this: http://github.com/jdhollis/factory_girl/commit/d77bb82ef104458cc1d8b0f1b78caaa91332f8d5
It looks like you switched to Gemcutter for the 1.2.3 release, but the README still has installation instructions pointing to thoughtbot-factory_girl
on GitHub. I forked and fixed it:
chrisk/factory_girl@8a4c1c0fb46333aa76dae4b3567b6a1bdd150854
The commit is tagged readme_gemcutter
for easy merging.
We've got quite a few namespaced models in our codebase, and so far we've had no troubles specifying factories for them like so:
factory :namespace_foo, :class => Namespace::Foo do |nsf|
nsf.foo 'foo'
nsf.bar 'bar'
end
However now working with Spork in our specs, I'm trying to prevent the constants from being loaded so early, so I changed all the constants to strings.
factory :namespace_foo, :class => 'Namespace::Foo' do |nsf|
nsf.foo 'foo'
nsf.bar 'bar'
end
But now all my factories break with NameError Exception: wrong constant name
This is just a simple matter of changing the way that factory_girl calls Object#const_get
. I'm forking and I'll link a branch with the fix shortly.
I've been bitten a few times recently by accidentally defining two factories with the same name. Factory_girl accepts this silently. I think an error is warranted: I can't think of a scenario where users are benefited by this ability and doing it inadvertently is likely to break things.
Here's my implementation. Attempting to define a second factory with the same name raises a DuplicateDefinitionError:
http://github.com/r00k/factory_girl/tree/disallow_duplicate_factory_definitions
rcov, rspec, cucumber, rr, sqlite3, activerecord
Reported by Vladimir Andrijevik
Hi folks!
First off, I love factory_girl. Very well done, and thank you!
I'm writing to you about a weird issue I found with has_many associations in factories. I've tried to make this example as minimalistic as possible:
in test/factories.rb
Factory.define(:team) do |team| team.sequence(:name) { |n| "Team #{n}"} end Factory.define(:user) do |user| user.sequence(:name) { |n| "User #{n}"} user.association(:team) end Factory.define(:team_with_users, :parent => :team) do |team| team.users { |users| [users.association(:user)] } end
With these factories defined, trying to create a team with users in the tests looks like this:
team = Factory(:team_with_users) Team Create (0.5ms) INSERT INTO "teams" ("name", "updated_at", "created_at") VALUES('Team 1', '2009-05-11 17:12:47', '2009-05-11 17:12:47') User Create (0.4ms) INSERT INTO "users" ("name", "team_id", "updated_at", "created_at") VALUES('User 1', 996332878, '2009-05-11 17:12:47', '2009-05-11 17:12:47') Team Create (0.4ms) INSERT INTO "teams" ("name", "updated_at", "created_at") VALUES('Team 2', '2009-05-11 17:12:47', '2009-05-11 17:12:47') #
As you can see, two teams are created, and the user object is associated with the wrong team. However, calling team.users will show the user object (because it's set with the users= setter), but on team.reload the users association appears empty.
team.users [#] team.reload.users []
Reported by Peter Suschlik
Branch on github: http://github.com/splattael/factory_girl/tree/global_default_strategy
It's like :default_strategy
option but for all factories:
Factory.global_default_strategy = :build Factory.define(:post) {} ... Factory(:post) # => like Factory.build(:post)
No need for :default_strategy => :build
every time.
Note:
I don't like the name global_default_strategy.
Factory.default_strategy = :build
would be nicer but I didn't want to hack up the current default_strategy method.
ActiveRecord and DataMapper share a significant amount of API. Enough at least to allow factory_girl to work with both. The following patch maintains compatibility.
I have to redefine associations in factories, even if the parent factory defines them already.
Hi,
There is a typo in README.rdoc. "startegy" instead of "strategy." Here is the commit you can pull in: akahn/factory_girl@8afb333
Cheers,
Alex
Reported by Nathaniel Bibler.
It would be of great benefit for factory_girl to support transition callbacks. This would allow for modification of the factory instance at distinct points in time.
It seems like useful instances in a Factory instance's life are: before_build, after_build, before_save, after_save.
This would allow, among other things, stubbing and mocking to be defined at the Factory level. This can be useful when working with models which have several associations, for example. This would alleviate the need to define all associations through other factories (user, posts, comments, etc.).
Murray Steele appears to have a basic working example of this as a fork of the project in GitHub (http://github.com/h-lame/factory_girl/commits/master/), as found through the Google Group at http://groups.google.com/group/factory_girl/browse_thread/thread/2220b8aba66f6ad4?fwc=1.
When factory girl is loaded, this code does nothing when run in the rails console:
ActiveRecord::Base.logger = Logger.new(STDOUT)
The expected behavior should be that ActiveRecord SQL statements are logged in the rails console. Factory_girl should not change this behavior.
When creating a factory that has a parent defined, attributes defined in blocks don't have scope to parent attributes because the parent's attributes haven't been added to the factory yet.
<script src="http://gist.github.com/165346.js"></script>I've created a branch that resolves this incorrect behavior: http://github.com/joshuaclayton/factory_girl/commits/parent-attributes-in-attribute-blocks
/lib/factory_girl/step_definitions.rb
Given /^(\d+) #{factory.human_name}s exist$/ do |count| count.to_i.times { Factory(factory.human_name) } end
It's does not work
This bug has been fixed here http://github.com/romanvbabenko/factory_girl
I sent you pull request
Hello,
I love Factory Girl and was turned on to it by a guy who used to work with you guys.
I create factories in unit and functional test files. However, the objects described by the factory appear in the database I was running when I ran the tests. Shouldn't they only appear in the test db?
Thank you very much for your time,
Misha
Reported by sandro
I'm pretty excited about factory stubs but I thought for sure the stub would support query? and bang! methods.
Factory.stub :user, :adult? => true, :suspend! => true
Here's my first stab at implementing this feature:
http://github.com/sandro/factory_girl/commits/stub_methods_not_attrs
user factory is singleton (with email [email protected] and email has validates uniqueness of), now a product is build with a user association -> singleton user is build indirectly. When the product is saved the build user-singleton is saved -> boom duplicate email. This happens especially often when there are a lot of factories, and somewhere deep down in the association chain a singleton is build.
i wrote this small "hack" to not allow indirect building of singletons (direct building is ok).
class Factory::AttributeProxy
def association(name, attributes = {})
if strategy == :attributes_for
nil
else
s = strategy
is_singleton = Factory.factories[name].instance_variable_get("@options")[:singleton]
s = :create if is_singleton and s == :build
Factory.send(s, name, attributes)
end
end
end
The association section of the readme has a couple of typos in it.
Here's my fix: http://github.com/paulgillard/factory_girl/tree/readme_typo_fix
I took a crack at it:
http://github.com/r00k/factory_girl/tree/update_readme_with_callbacks
http://github.com/erikh/factory_girl
Patch adds proxy-specific Factory.define options.
Patch adds a :singleton_on attribute to Factory.define; see README.rdoc for use-case information, but the basic gist is that when going through the create proxy, the value of the :singleton_on parameter is used on the generated instance to find a target, which is then searched for in the model the instance was created from. If an object is found, it is used instead of creating a new one, and then saved.
Tests added, pull request sent, working in real-world scenarios already.
Sometimes you want to define your own "id" attribute on an AR model. Maybe you want it to be a String, or maybe you don't want Rails to auto-generate this value. Current you can cannot define a Factory with such an attribute.
Factory.define(:student) do |s|
s.id "some_valid_student_id"
s.first_name "Joe"
s.last_name "Smith"
end
/Users/daniel/.rvm/gems/ruby-1.9.1-p378/gems/railties-3.0.0.beta/lib/rails.rb:40:in configuration': undefined method
config' for nil:NilClass (NoMethodError)
from /Users/daniel/km/sio/trunk/vendor/bundle/gems/factory_girl-1.2.3/lib/factory_girl.rb:25:in <top (required)>' from /Users/daniel/km/sio/trunk/vendor/bundle/gems/bundler-0.9.13/lib/bundler/runtime.rb:45:in
require'
from /Users/daniel/km/sio/trunk/vendor/bundle/gems/bundler-0.9.13/lib/bundler/runtime.rb:45:in block (2 levels) in require' from /Users/daniel/km/sio/trunk/vendor/bundle/gems/bundler-0.9.13/lib/bundler/runtime.rb:40:in
each'
from /Users/daniel/km/sio/trunk/vendor/bundle/gems/bundler-0.9.13/lib/bundler/runtime.rb:40:in block in require' from /Users/daniel/km/sio/trunk/vendor/bundle/gems/bundler-0.9.13/lib/bundler/runtime.rb:39:in
each' from /Users/daniel/km/sio/trunk/vendor/bundle/gems/bundler-0.9.13/lib/bundler/runtime.rb:39:in require' from /Users/daniel/km/sio/trunk/vendor/bundle/gems/bundler-0.9.13/lib/bundler.rb:73:in
require' from /Users/daniel/km/sio/trunk/config/application.rb:6:in <top (required)>' from /Users/daniel/km/sio/trunk/config/environment.rb:2:in
require'
from /Users/daniel/km/sio/trunk/config/environment.rb:2:in `<top (required)>'
I get this error when I run something as simple as "rails console"
let me know if I can expand
I've been able to avoid it most part because factory_girl is only loaded in the test environment. But it also means I can't run tests using factory girl.
if defined? Rails.configuration and Rails.application in factory_girl.rb solves the problem, but this probably isn't the correct solution.
This maybe just needs documentation update, but in my rails 2.x app (and in the factory_girl README), this was fine:
Factory.define :admin_user, :class => User do |u|
In Rails 3 using your 'rails3' branch, that now blows up w/uninitialized constant User
Changing User to a symbol fixes it:
Factory.define :admin_user, :class => :user do |u|
Factory.attributes_for(:appointment)
=> {:provider=>nil, :patient=>nil, :start_time=>"8:00", :end_time=>"10:00", :office=>nil}
but
Factory.build(:appointment).attributes
=> {"kind"=>nil, "end_time"=>Thu, 24 Dec 2009 10:00:00 UTC +00:00, "created_at"=>nil, "provider_id"=>101, "updated_at"=>nil, "patient_id"=>21, "appointment_date"=>nil, "description"=>nil, "start_time"=>Thu, 24 Dec 2009 08:00:00 UTC +00:00, "office_id"=>51}
I'm withdrawing this issue, as after reading the source it's become obvious that:
Reported by Eric Mill
In ActiveRecord, you can't set the created_at or updated_at timestamps through the use of #save. At best, you can update the created_at timestamp by using #update_attribute in a second command after the object has been created, but you can't get away with even that for updated_at -- you have to execute SQL.
Since setting created_at and updated_at timestamps are often useful in test environments, I'm asking that FactoryGirl have a special case for created_at and updated_at that lets them be overridden.
The following should work as expected:
user = Factory :user, :created_at => 2.days.ago, :updated_at => 1.day.ago user.created_at #=> 2 days ago user.updated_at #=> 1 day ago user = Factory.build :user, :created_at => 2.days.ago, :updated_at => 1.day.ago user.save user.created_at #=> 2 days ago user.updated_at #=> 1 day ago
The latter seems much more difficult to implement than the former -- the only way I could think to do it would be to instance_eval an after_create callback on the built object, to make sure that it'd get updated appropriately down the line. However, I'd be happy even if only the first form works.
Similarly, the following should work as expected:
Factory.define :user do |u| u.created_at {Factory.next :user_created_at} end Factory.sequence(:user_created_at) {|i| i.days.ago}
I'm interested in hearing people's opinions on this.
Reported by Joe Ferris
Proxy objects are responsible for returning values of previously defined attributes, but you can't reference "id" and other attributes that conflict with methods on Object.
Proxy should either undefine these methods so that method_missing is called, or directly delegate them to #get.
spec.add_dependency("activesupport") should be enough
Example:
Factory.define :product do |p|
st.sequence(:id) { |n| "123456ABCDE#{sprintf("%04d", 1000+n)}"}
st.price 200
end
Error:
ActiveRecord::RecordInvalid in 'Product Testing validations before(:all)'
Validation failed: Product product_id.validates_presence_of
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.