Alternatives to factory_girl - ruby-on-rails

In my opinion and for my purposes, factory_girl completely sucks. Some limitations include:
No debugging support
If I include debugger statements, they are treated as model attributes. Instead of invoking the debugger, I just get strange errors.
FactoryGirl.define do
factory :admin do
name do
debugger # <-- Does not work.
Forgery(:name).full_name
end
email { Forgery(:email).address }
debugger # <-- Does not work either.
password "secret"
end
end
Limitations to associations
Am I too stupid or is there no elegant way to add two posts to a user?
FactoryGirl.define do
factory :post do
title "Foobar"
content "Some content"
end
factory :user do
name { Forgery(:name).full_name }
email { Forgery(:email).address }
# This does not work, if the Post model requires Post#user to be set.
posts [FactoryGirl.create(:post), FactoryGirl.create(:post)]
end
end
See also Factory Girl - Why are Records being continually created?
Tends to trigger strange bugs in rails
I can't remeber what happend, but often strange problems arise with factory_girl.
So given these examples. Are there any alternatives to factory_girl that do not have these issues?

I agree and found Factory Girl overly complicated for what it does.
I wrote a simpler gem a while ago which (at the time at least) was a drop in replacement for Factory Girl-based tests.
The factory definitions use much simpler Ruby and therefore behave as you would expect them to.
Check it out:
https://github.com/ginty/cranky

Why are you debugging inside the factory definition instead of in your code on the resulting objects?
And what's wrong with
user = FactoryGirl.create(:user)
2.times do
FactoryGirl.create(:post, user: user)
end

A debugger statement in a DSL can be problematic. You don't know when it will run.
FactoryGirl could run the DSL, save a representation of the factory, and use the internal representation in memory when the factory is used.
Also, there is no variable to inspect except self. The self is going to be a germ object to build the definition.
At the risk of answers all being defense of FactoryGirl, if your alternatives to FactoryGirl are DSLs to populate data, you are still going to have the problem of debugging support.
Alternatives include fixtures and just calling ActiveRecord to populate test data. Really FactoryGirl doesn't have much over ActiveRecord, it's just more symbol oriented calls, so people get to make meaningful symbol names which is all FactoryGirl was supposed to do.
You cannot put a debugger statement in the middle of a fixture, or in the middle of a hash that you are sending to a create method, but at least you won't be tempted to.
(The See also Factory Girl - Why are Records being continually created?, was an example where FactoryGirl was working perfectly, but the user told it to create four records, and then was surprised when it created four records.)
So maybe if you stick with fixtures and ActiveRecord calls things will be dumbed down enough that you won't get confused.

Related

How do i check the valid association and the related model existence

I am following this pattern
it { is_expected.to respond_to(:cars) } for checking the association
Now accidentally in the model, let's assume I have this line
has_many :bars
So in the test, after seeing the model. I went ahead and did this
it { is_expected.to respond_to(:bars) }
And the test passes, but there is no model Bar how do we rectify this.
has_many :bars adds many methods to your model, bars is one of them, and respond_to matcher just check if there's such publicly available method - so you don't really testing what you think you would like to test.
You could for example do something like this:
expect(subject.bars.build).to be_instance_of(Bar)
This spec would fail if Bar does not exist.
I'm also pretty sure that
expect(subject.bars).to eq []
Would fail too, since it should try to find those in the DB, and missing model would surface here as well.
Also this
expect{ subject.bars.build }.not_to raise_exception
should also fail.
That's generally the problem with dynamic languages - errors (including typos) are not immediately caught.
I actually didn't know that you can define a relation to unexisting model. But it makes sense - checking if the classes exists during the class definition could be a bit too heavy.
I have an answer in a few parts. First, you can help avoid these typos of errors by test-driving your implementation. If you write a failing test first, the error message is another opportunity for you to recognize the typo: "Wait, a minute... it doesn't make sense for this to respond to bars. That's not what I meant..."
The larger answer is that this test on its own has so little value as to be worthless. If you make the typo above in both the implementation and that test and no other test fails then it's hard for me to believe it matters at all if the object response to cars, bars or any other typo.
A more valuable test would exercise the behavior of the association. For instance, if you wanted to test that a Person could associate a Car to their user, you could start with a feature test that exercises that feature. The test failure would guide you toward a working implementation that may or may not require that association. But if you typo the association you will find out because you are testing actual behavior.

FactoryGirl "create_list" not saving to database

I'm seeing some weird behaviour in FactoryGirl that seems to contradict the documentation. In an Rspec test, if I do this;
static_groups = FactoryGirl.create_list(:static_group,5)
expect(StaticGroup.count).to eq(5)
The test fails (expected: 5, got: 0). If I add in explicit saves of the records;
static_groups = FactoryGirl.create_list(:static_group,5)
static_groups.each do |grp|
grp.save
end
expect(StaticGroup.count).to eq(5)
The test passes! I thought "create" in factorygirl was supposed to do a save for you, but in this case it is plainly not saving records which can be saved straight away afterwards! Even weirder, if I interrogate the objects in the first example (where I don't do an explicit save) they all have ids, so they've definately been talking to the database!!
EDIT
Before anyone points out the dodgy "count" syntax, I'm using DataMapper as an ORM, that's a valid way of counting :)
Ugh - nightmare.
Eventually figured out what it was - the "StaticGroup" class uses STI to figure its type out. This is a little more complex because it hooks into two databases and the class structure changed between legacy and new-world.
Long story short, I copy/pasted my group factory into the static group factory and forgot to change the type. There was a hook in the "save" method that sorts this out for me and it wasn't getting fired when factorygirl created the object.

Is it a bad idea to write invalid FactoryGirl factories/traits?

Listening to Giant Robots Smashing Into Other Giant Robots podcast, I heard that you want your FactoryGirl factories to be minimal, only providing those attributes that make the object valid in the database. That being said, the talk also went on to say that traits are a really good way to define specific behavior based on an attribute that may change in the future.
I'm wondering if it's also a good idea to have traits defined that purposefully fail validations to clean up the spec code. Here's an example:
factory :winner do
user_extension "7036"
contest_rank 1
contest
trait :paid do
paid true
end
trait :unpaid do
paid false
end
trait :missing_user_extension do
user_extension nil
end
trait :empty_user_extension do
user_extension ""
end
end
will allow me to call build_stubbed(:winner, :missing_user_extension) in my specs in tests I intend to fail validations. I suppose I could further this explicit fail by nesting these bad factories under another factory called :invalid_winner, but I'm not too sure if that's necessary. I'm mostly interested in hearing others' opinions on this concept.
No it's not a good idea, it wont make your specs clear to understand after a while, and later when your code evolve those factory that fail today may not fail anymore, and you would have hard time to review all your specs.
It is way better to write your test for one clearly identified thing. If you want to check that saving fails with a mandatory parameter missing, just write it with your regular factory and add parameters to overwrite the values from the factory:
it 'should fail' do
create :winner, user_extension: nil
...
end

When is a good time to test associations with Shoulda?

With RSpec and Shoulda you can:
it { should belong_to(:product) }
I am told specs should specify observed behavior. This spec also does seem like duplication of code that can be written in the model. So is there a time and place to actually use a test like this?
The bigger question is, why is it bad to test this? If you are told specs should specify observed behaviour, and a model having a belongs_to automatically gives it a method to access the association, is that not something to observe? You could test the #product method instead, but how would that test go?
it "has an association to a product" do
product = Product.create
model = Model.create(:product_id => product.id)
model.product.should eq product
end
Is that really better than just using the single liner?
it { should belong_to(:product) }
If the code is in any way important, you should test it.
Furthermore, if you were following TDD, you would write the test first to specify that an association has to be there, then put in the code to maintain that test.

Setting up a test in rspec with multiple "it" blocks

Say I have an instance method that does many different things that I need to test, something like store#process_order. I'd like to test that it sends an email to the customer, adds an entry in the orders table, charges a credit card, etc. What's the best way to set this up in rspec? Currently, I'm using rspec and factory girl I do something like this:
describe Store do
describe "#process_order" do
before do
#store = Factory(:store)
#order = Factory(:order)
# call the process method
#store.process_order(#order)
end
it 'sends customer an email' do
...
end
it 'inserts order to db' do
...
end
it 'charges credit card' do
...
end
end
end
But it feels really tedious. Is this really the right way to write a spec for a method that I need to make sure does several different things?
Note: I'm not interested in answers about whether or not this is good design. It's just an example I made up to help w/ my question - how to write these types of specs.
This is a good method because you can identify which element is broken if something breaks in the future. I am all for testing things individually. I tend not to check things get inserted into the database as you are then rails functionality. I simply check the validity of the object instead.
This is the method that is used in the RSpec book too. I would certainly recommend reading it if you are unsure about anything related to RSpec.
I think what you are doing is fine and I think it's the way rspec is intended to be used. Every statement (specification) about your app gets its own block.
You might consider using before (:all) do so that the order only has to get processed once but this can introduce dependencies on the order the specs are run.
You could combine all the code inside describe "#process_order" into one big it block if you wanted to, but then it would be less readable and rspec would give you less useful error messages when a spec fails. Go head and add raise to one of your tests and see what a nice error message you can get from rspec if you do it the way you are currently doing it.
If you want to test the entire process then we're talking about an integration test, not a unit test. If you want to test #process_order method which does several things, then I'd expect those things mean calling other methods. So, I would add #should_receive expectations and make sure that all paths are covered. Then I would spec all those methods separately so I have a nice unit spec suite for everything. In the end I would definitely write an integration/acceptance spec which checks if all those pieces are working together.
Also, I would use #let to setup test objects which removes dependencies between spec examples (it blocks). Otherwise a failure of one of the examples may cause a failure in other example giving you an incorrect feedback.

Resources