[LRUG] Large Slow Test Suites

Sam Livingston-Gray geeksam at gmail.com
Thu Dec 5 09:34:47 PST 2013


And speaking of antipatterns commonly encountered when using Rails, there's
the God Object.

The way I usually find God Objects is by running this from the root of my
Rails project:

$ find app/models -name '*.rb' | xargs wc -l | sort | tail

When I do this, I almost always see app/models/user.rb, along with the
names of the two or three objects that are central to the app's domain.  In
one memorable project, the last file on the list was about 3,500 lines—but
when I added in line counts from all of the modules that had been mixed in
to the class, the total was pushing 10K.  o_O

The only solution I was able to come up with (other than working in a
strictly quarantined subpath of the app and pretending the rest of it
wasn't there) was to employ this pattern when adding new methods that had
to touch the God Object:

class BigHonkingModel < ActiveRecord::Base
  # ... loads of code

  def my_new_feature(*args, &block)
    MyNewFeatureCollaborator.new(self).call(*args, &block)
  end
end

This accomplishes three things:

1) It helps me not be the jackass who finally pushes the line count above
10K (I only added four lines, including the load-bearing whitespace!).
2) It puts all of the new logic into a collaborator object that gets its
primary dependency injected at initialization time—which makes it much,
much easier to write fast tests for everything that collaborator does.
 (And here you thought I was going off topic...)
3) Because my collaborator's logic is in a separate class, it's limited* to
calling public methods of BigHonkingModel.  My fast test setup injects a
double, and the pain of having to mock the public methods that will be
called on that double helps keep my collaborator's responsibilities
relatively focused.

* (Well, I say "limited".  It's still Ruby, so you can #send all you want.
 As long as you can still sleep at night.  You monster.)

By no means am I suggesting that this is a "best practice".  For starters,
I'm continuing to violate SRP by adding yet another method to a model
that's already got far too many of them.  But I suggest that it is, at
least, a "less awful practice" that helps you slow your descent into
madness while you condition your customers to accept longer delivery times
so you can start making installment payments on your tech debt.

-Sam


On Wed, Dec 4, 2013 at 2:20 PM, Mr Jaba <the.jaba at gmail.com> wrote:

> Hi Everyone,
>
> I've recently taken ownership of a new project with a large test suite
> (2000ish tests), and the overall run time is around 30 minutes which is
> certainly less than ideal!
>
> Now I know the general approach to "Fast Rails Tests" but taking the time
> to refactor the whole test suite is a bit too much right now. I'm wondering
> if anyone has experience of transforming a test suite of this magnitude to
> something a bit speedier? If so how did you go about it? What tips, tricks
> and techniques can you share?
>
> A bit more info:
>
> - Test::Unit tests, moving to Minitest
> - Rails 3.2.16
> - Running parallel_tests shaved 5 mins off the time
> - Using Spring to reduce Rails load time.
>
> Any advice gratefully received!
>
> Tom
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.lrug.org/pipermail/chat-lrug.org/attachments/20131205/5782b39d/attachment-0003.html>


More information about the Chat mailing list