Earlier quoted context omitted.
That's where we find ourselves currently: constructing 3-4 levels out due to Law of Demeter violations, and it becomes incredibly brittle when seemingly unrelated classes change. IMO, DHH (and others) argue too hard against core OO principles (like SRP and LoD) that have the possibility of helping out when the domain model becomes more complex. "Just use Rails" is fine when spinning up, but as the app grows, it becom…
As an FYI to your last point - in Rails master (which will be Rails 4), you can active-record-ify a class by including ActiveRecord::Model, rather than inheriting from ActiveRecord::Base. In fact, that is all ActiveRecord::Base does itself - https://github.com/rails/rails/blob/master/activerecord/lib/... .
Rails Testing with Factory Girl
21–30 of 36 posts
Re: Rails Testing with Factory Girl
#22You can use build instead of create to avoid the db, as per previous comments. You don't have to use it at all if writing a simple unit test.
But for teeing up complex scenarios prior to a fat integration test, it rocks.
Re: Rails Testing with Factory Girl
#23I hate when people are using it in the unit tests. It just makes testing very convenient, so they start using it everywhere. In the end, the test suite gets very slow. Unit tests should not hit the database. First example there: test_new_customer_defaults. Really, it needs 3 saved models to test this? FactoryGirl isn't solution here. It's just hiding the problem.
Yep, I'm trying to dig myself out from this problem now. The Rails Tutorial (railstutorial.org) uses Factory Girl and integration tests for just about everything, which is a fast enough approach for its toy application, but I've found that when your application gets more complex your test suite takes forever to run, and setting up the tests gets more and more painful (especially when you start dealing with external A…
[1]: http://objectsonrails.com/
I'm not sure if it's the best resource, though. I'd love to hear other opinions.
Re: Rails Testing with Factory Girl
#24I hate when people are using it in the unit tests. It just makes testing very convenient, so they start using it everywhere. In the end, the test suite gets very slow. Unit tests should not hit the database. First example there: test_new_customer_defaults. Really, it needs 3 saved models to test this? FactoryGirl isn't solution here. It's just hiding the problem.
One compromise (edit: on the performance problem) would be to use FactoryGirl to generate some type of (yaml?) cache pre-test-run, automatically refreshing only when the model changes.
Edited to add: Using FactoryGirl to generate a cache only addresses the performance issues without addressing the complexity-hiding problem.
Re: Rails Testing with Factory Girl
#25Earlier quoted context omitted.
One compromise (edit: on the performance problem) would be to use FactoryGirl to generate some type of (yaml?) cache pre-test-run, automatically refreshing only when the model changes.
I think you're missing the point of what makes FactoryGirl an anti-pattern in unit tests. FactoryGirl reduces the feedback that you can get from unit tests by hiding complexity (of creating objects), which your unit tests are supposed to make apparent. Edited to add: Using FactoryGirl to generate a cache only addresses the performance issues without addressing the complexity-hiding problem.
If performance wasn't an issue, the convenience of auto-created objects would mean more 'unit' tests (edit: usually closer to integration tests) that wouldn't exist otherwise. Sure it's best to de-couple things, but there's room for something between no [unit] tests at all and perfect unit tests.
Re: Rails Testing with Factory Girl
#26Earlier quoted context omitted.
One compromise (edit: on the performance problem) would be to use FactoryGirl to generate some type of (yaml?) cache pre-test-run, automatically refreshing only when the model changes.
I think you're missing the point of what makes FactoryGirl an anti-pattern in unit tests. FactoryGirl reduces the feedback that you can get from unit tests by hiding complexity (of creating objects), which your unit tests are supposed to make apparent. Edited to add: Using FactoryGirl to generate a cache only addresses the performance issues without addressing the complexity-hiding problem.
Complexity is a moot point for those extraneous objects. You want that complexity out of the tests since it's not the focus of the test itself, and makes it more readable.
But I'll take this one step further. To each their own. There is no one exact correct way. Do what's right for your code, domain, and tests. I wouldn't test an API codebase the same I would a site codebase or a gem codebase anyways.
Re: Rails Testing with Factory Girl
#27Earlier quoted context omitted.
I think you're missing the point of what makes FactoryGirl an anti-pattern in unit tests. FactoryGirl reduces the feedback that you can get from unit tests by hiding complexity (of creating objects), which your unit tests are supposed to make apparent. Edited to add: Using FactoryGirl to generate a cache only addresses the performance issues without addressing the complexity-hiding problem.
I could also argue that's exactly WHY to use factory girl in unit tests. You're not using FG to create the things under test, only the things to pass to the thing under test. Complexity is a moot point for those extraneous objects. You want that complexity out of the tests since it's not the focus of the test itself, and makes it more readable. But I'll take this one step further. To each their own. There is no one e…
If you're using your unit tests to inform your design, then the complexity in the extraneous objects is relevant, because they tell you how coupled your unit under test is to its dependencies. This is what FactoryGirl hides from you.
I tend to use fake objects for the collaborators. Usually just a vanilla test double will do, but sometimes I use RSpec's stub_model if the collaborator has to behave more "model-like".
I'd recommend http://pyvideo.org/video/631/fast-test-slow-test and http://www.confreaks.com/videos/641-gogaruco2011-fast-rails-... if you haven't seen them already.
Re: Rails Testing with Factory Girl
#28Earlier quoted context omitted.
I could also argue that's exactly WHY to use factory girl in unit tests. You're not using FG to create the things under test, only the things to pass to the thing under test. Complexity is a moot point for those extraneous objects. You want that complexity out of the tests since it's not the focus of the test itself, and makes it more readable. But I'll take this one step further. To each their own. There is no one e…
I would argue that those aren't unit tests, because they depend on the collaborators that you're passing into the unit under test. A change to those objects could break your unit test. That makes it an integration test. If you're using your unit tests to inform your design, then the complexity in the extraneous objects is relevant, because they tell you how coupled your unit under test is to its dependencies. This is…
Tests and code don't always fall into these neat cult buckets we've drawn up for ourselves. Good doesn't mean just fast. It can also mean readable, to wit FG usage addresses quite nicely. Just another tool in the toolbox.
Just like ruby, I can write crap tests with or without FG and great tests with or without FG. Same goes for stubs, doubles, and collaborators.
Re: Rails Testing with Factory Girl
#29Earlier quoted context omitted.
You can use the build method to instantiate the model without saving to the database. Very useful because you only need use create when you need persistence in your test - such as when testing a controller.
Remember to ensure that your build strategy is set on all associations if you want this to work, e.g. FactoryGirl.define do factory :user do association :account, :strategy => :build end end Otherwise when you build a user, the account association will still get persisted to the database. Even if you do this, though, you're still spinning up a whole network of real objects in what is supposed to be a unit test.
factory :user # sets only user fields, no relations
factory :account # sets only account fields, no relations
factory :user_account {creates both}
When you have a large # of tests/factories, it's nearly impossible to keep track over time what the :user factory creates. Today it's one relation. Years from now, it could be 10 other tables relations. Someone later on decides they want to reuse the :user factory, but they don't want the account to be create, so then they do :user_only factory. Yada yada. Shenanigans ensue.If you stick to the above strategy, things are much faster, but more importantly, there are less unintended surprises, like associations doing a create instead of a build, etc.
Re: Rails Testing with Factory Girl
#30Earlier quoted context omitted.
I could also argue that's exactly WHY to use factory girl in unit tests. You're not using FG to create the things under test, only the things to pass to the thing under test. Complexity is a moot point for those extraneous objects. You want that complexity out of the tests since it's not the focus of the test itself, and makes it more readable. But I'll take this one step further. To each their own. There is no one e…
I would argue that those aren't unit tests, because they depend on the collaborators that you're passing into the unit under test. A change to those objects could break your unit test. That makes it an integration test. If you're using your unit tests to inform your design, then the complexity in the extraneous objects is relevant, because they tell you how coupled your unit under test is to its dependencies. This is…
I think we need the same thing in programming.
If it's slow, make it faster. If it's unreadable, make it readable. If it's coupled, decouple it.
Then just stop worrying if we fall into official definitions of unit, integration, collaborator, mock, stub, double, etc. I swear we spend more time as an industry arguing about that stuff than actually writing code, myself included.