Want to speed up your test suite? Reduce the number of objects persisted to
the database. With Factory Girl, this is really easy; instead of using build
or create to instantiate your models with data, use build_stubbed!
build_stubbed is the younger, more hip sibling to build; it instantiates
and assigns attributes just like build, but that’s where the similarities
end. It makes objects look look like they’ve been persisted, creates
associations with the build_stubbed strategy (whereas build still uses
create), and stubs out a handful of methods that interact with the database
and raises if you call them. This leads to much faster tests and reduces your
test dependency on a database.
For example, let’s say we have an OrderProcessor that accepts instances of
Order and CreditCard. It hits the Braintree API and returns a boolean
value for if the charge actually happened.
class OrderProcessor
def initialize(order, credit_card)
@order = order
@credit_card = credit_card
end
def process
charge_successful? charge_customer
end
private
def charge_successful?(result)
# processes the result to determine if the result is valid,
# operating on the order and credit_card instance variables to
# add errors, send emails, or track Braintree's transaction id
end
def charge_customer
# runs Braintree::Customer.sale() with the appropriate options
end
end
None of this code hits the database. This allows us to write tests like:
describe OrderProcessor do
let(:transaction_id) { '1234' }
let(:order) { build_stubbed(:order) }
let(:credit_card) { build_stubbed(:credit_card) }
subject { OrderProcessor.new(order, credit_card) }
context 'when the Braintree result is valid' do
before do
MockBraintree.stub_successful_customer_sale(transaction_id: transaction_id)
end
it 'assigns the transaction id to the order' do
subject.process
order.transaction_id.should == transaction_id
end
it 'returns true for #process' do
subject.process.should be
end
it 'does not assign any errors to the credit card' do
subject.process
credit_card.errors.should be_empty
end
end
context 'when the Braintree result is invalid' do
before do
MockBraintree.stub_unsuccessful_customer_sale
end
it 'does not assign the transaction id to the order' do
subject.process
order.transaction_id.should be_nil
end
it 'returns false for #process' do
subject.process.should_not be
end
it 'assigns errors to the credit card' do
subject.process
credit_card.errors.should_not be_empty
end
end
end
Instead of creating twelve different records (at the minimum - if any of these factories have associations, you introduce more multipliers), we create none. This keeps the spec blazing fast.
Properly factored code should be small and concise. Code should typically depend
less on the state of the data in relation to the database and more on its
state in relation to other objects. In the above example, OrderProcessor
only handles dealing with Braintree and dealing with its errors; it does not
care about how this data is displayed to the user. That’s left for the
integration tests, which should be hitting the database.
Although it’s not useful in every situation (there are cases where you’ll want
data to exist, like when you’re testing uniqueness constraints or scopes),
build_stubbed should be your go-to FactoryGirl method over build or
create. Everyone running your test suite (yes, even yourself) will thank you.
There’s a new version of factory_girl this week, as usual: 3.1.1 (aa81d2f).
Mark Rushakoff (mark-rushakoff) fixed a typo (4682ab0). Have I mentioned how much I love documentation fixes? Because I do.
Joshua Clayton (joshuaclayton) ensured that FactoryGirl.attributes_for works with has_many associations (50be545).
He also refactored Strategies to be modules instead of classes, and added an Evaluation façade to make building strategies easier (89d5e94).
flutie got some love this week from Edwin Morris (ehmorris), who changed values from pixels to ems (fd26ed0) and these new-fangled CSS3 “rems”. REMs are relative to the base element’s size, not to the parent’s size (more here). I wish I’d had that back in the day.
paperclip got a bunch of bug fixes from Prem Sichanugrist (sikachu). He fixed the content_type validator to allow blanks and nils (5eed1dc), ensured that code dealt with the content type, not the MimeType (3f1d30f), closed ALL the files (4f6d482), and removed unused code (yay!) (02eb725).
Sebastien Guignot (sguignot) fixed attachment.reprocess! when using Fog or S3
(9d1355b).
Kir Maximov (kir) fixed a problem with an incorrect content_type (3e98fc2).
shoulda-matchers continues to improve. Gabe Berke-Williams (gabebw - that’s me!) added tests for Rails 3.2 (aff2824) and bumped rspec-rails (5baa056). As ever, the NEWS file is the place to watch for updates to functionality.
Aaron Gibralter (agibralter) fixed
the ensure_length_of matcher to check for all possible I18n error
messages (0a8e652),
meaning our internationalized users aren’t left with false negatives in their
tests.
Victor Pereira (vpereira) added the
in_array method (e40e2cb)
to the ensure_inclusion_of matcher, meaning you can do
it { should ensure_inclusion_of(:attribute).in_array(%w[cat dog]) now.
Gabe Berke-Williams (gabebw - that’s me!) cleaned up the clearance Rakefile a bit (4f016db).
Joshua Clayton (joshuaclayton) released version 3.1.0 of factory_girl (f1d3018). For the full list of changes, see the NEWS file. Josh updated a few dependencies too (20becc9, 29157d6). Kristian Mandrup (kristianmandrup) added the ability to alias sequences, just like you can alias factories (f387e38, 178a7ab). To see how to use it, see the documentation (f013335) he added for it. I love documentation pull requests.
Joshua Clayton (joshuaclayton) bumped factory_girl_rails to version 3.1.0 (4259e4c) to match factory_girl’s new version.
Prem Sichanugrist (sikachu) released version 3.0.2 (240147e) of paperclip. Unfortunately, the NEWS file hasn’t been updated for 3.0.2 yet. Prem removed an obsolete generator, then added a test for it (a2a4c7a, 03700c8). Preston Guillory (pguillory) fixed a typo (853595a). Typo fixes are always welcome! Michael Galero (mikong) pluralized the table name in the migration generator to follow Rails convention (28e2d1b). And Rafael Mendonça França (rafaelfranca) removed init.rb, since plugins will be deprecated in Rails 4.0 (ae7b7c5).
Gabe Berke-Williams (gabebw - me again!) finally released a new version of shoulda-matchers! Version 1.1.0 has a bunch of changes that you can see in the NEWS file. One of the noteworthy changes is that shoulda-matchers now depends on ActiveSupport >= 3.0.0 (c65e43a), meaning it’s Rails 3-only. We’ve been only testing against Rails 3 for a while, so this just makes it official. Gabe made a couple of documentation fixes (9203275, 8fcc3d2, a4edff0) and also cleaned up the code (5873502, 41088bc, 3039cc6, 820f216, 2e73b35, 457be62). Brendan Loudermilk (bloudermilk) added an accept_nested_attributes_for matcher (ee74222).
Finally, Gabe Berke-Williams (gabebw) fixed a little bug in this-week-in-open-source (which I used to generate this post!) to print missing directories before doing anything else (564c7c9).
You probably know about this Factory Girl definition syntax:
FactoryGirl.define do
factory :user do
name 'Connie Customer'
end
end
But did you know about this Factory Girl invocation syntax?
setup do
@user = create(:user)
end
Or:
setup do
@user = build(:user)
end
Or:
setup do
post :create, user: attributes_for(:user)
end
It’s in there.
Configuration for Test::Unit / Shoulda:
class ActiveSupport::TestCase
include FactoryGirl::Syntax::Methods
end
Configuration for RSpec:
RSpec.configure do |config|
config.include FactoryGirl::Syntax::Methods
end
Configuration for Cucumber:
World FactoryGirl::Syntax::Methods
So this bourbon gem…people seem to like it: there was a RailsCast about it and the principle author (Phil LaPier) will be speaking at Frontend United about it.
This week people cleaned up the obsolete CSS attributes: Thibaut (Thibaut) removed -moz-inline-block (d73ea46), Chad Mazzola removed both -ms-border-radius and -o-border-radius (10a5908), and Phil LaPier (plapier) removed -moz-box-orient (6331e26). Gabe Berke-Williams (gabebw) fixed support for Rails 2 (eacd5ee and e9347e7) and, lesson learned, removed Gemfile.lock (671ad33).
Version 2.6.3 of factory_girl is out, all y’all. In this action-packed version we got a cucumber step named e.g. Given the following post exists (note the lack of : at the end), via cj (cj) (d4b8cac and 48afe24). Barun Singh (barunio) fixed a bug where the factory’s traits weren’t compiled in the very first time the factory was used (68ca50f), plus a factory can use all the traits on any ancestor (f14a8cf). Joshua Clayton (joshuaclayton) is now listed as an author (07d2834), so congrats to him and his hard work. As part of that hard work he discovered that the vintage syntax broke in MRI 1.9.2-p318, and then fixed it (a7acc3e).
This just in! Version 3.0.0.rc1 is now public! It breaks everything, again! Please try it and open issues with what breaks:
gem 'factory_girl', '3.0.0.rc1'
Oh hey version 1.1.1 of bourne is out (650afb0)! Bourne is an extension to mocha that adds test spies so your tests can read like normal tests. Tristan Dunn (tristandunn) added support for mocha 0.10.5 (286d8f9) and fixed a long-standing error message that occurs when you forget to stub a method before spying on it (17dc7d2).
Gabe Berke-Williams (gabebw), who pushed the release, also did some maintainance: adding Travis CI notifications to the README (7d6eb37), removing Gemfile.lock (950a445), and some general code cleanups (4bbe610 and b0f1f99).
The big deal in shoulda-matchers over the past week was when Fujimura Daisuke (fujimura) added the ability to specify the key for the flash message in the set_the_flash matcher (0e0339e, ef866e2, and fd4aa53):
it { should set_the_flash[:alert].to("Password doesn't match") }
Gabe Berke-Williams (gabebw) did his usual maintainance of converting the docs to use Markdown (85c37c4), cleaning up the ModelBuilder that’s used in the tests (31595b0), and showing off how often our build is broken in the README using Travis CI (eebb806), which he also did to shoulda proper (7d805d0).
Also victim to the Travis CI treatment was cocaine, via Gabe Berke-Williams (gabebw) again (ac47b6f and 490c406).
The paperclip project is gearing up for a groundbreaking (maybe app-breaking?) release, but in the meantime Mike Boone (boone) fixed an infinitely-growing PATH environment variable (06d69af) while Mike Burns (mike-burns)—also known as: me—totally broke backward compatibility by changing the default :path and :url configuration setting (26f4d40). These new settings avoid overwriting files on different models and also scales to more than 1024 instances of the same model.
In capybara-webkit news, Joe Ferris (jferris) controversially allowed the user to interact with invisible elements (02f2a8a), and caught the fact that Capybara.timeout is deprecated (4d954b7).