Separating black sheep examples from the rest

So we’ve got a pretty decent number of specs now, and despite my best
efforts, AR is just forcing us down the path of having to use
database interaction for some of the model specs.

It’s starting to get tiring to run all the specs now, which is making
me sad, and making me worry about how things are going to be in a few
months from now.

I’d like to somehow be able to systematically mark the slow example
groups as being ‘impure’ and thus be able to choose to mostly ignore
them during my regular TDD cycle, just running them every so often as
a regression.

I’m thinking something like this:

describe “when there are ten users in the database”, :slow => true do

What do you think? How are other people solving this problem? Any
tips / thoughts on how I could implement this?

cheers,
Matt

http://blog.mattwynne.net

In case you wondered: The opinions expressed in this email are my own
and do not necessarily reflect the views of any former, current or
future employers of mine.

Matt W. wrote:

So we’ve got a pretty decent number of specs now, and despite my best
efforts, AR is just forcing us down the path of having to use database
interaction for some of the model specs.
Just out of curiosity, I would be interested to know how AR is forcing
you to use database interaction in your model specs. Can you give an
example?


Joseph W.
http://www.joesniff.co.uk

Matt W. [email protected] writes:

I’m thinking something like this:

describe “when there are ten users in the database”, :slow => true do

What do you think? How are other people solving this problem? Any tips /
thoughts on how I could implement this?

Why don’t you put the specs in a different directory? One layout that
I’ve seen used (I think by the WePlay guys) is:

spec/
integration/
controllers/
models/
unit/
controllers/
models/

Pat

Matt W. wrote:

them during my regular TDD cycle, just running them every so often as
a regression.

I’m thinking something like this:

describe “when there are ten users in the database”, :slow => true do

What do you think? How are other people solving this problem? Any tips
/ thoughts on how I could implement this?

Hey Matt,
In order to keep my object-level examples on the unit-test speed (less
than 0.1 sec) I have been using NullDB to disconnect my entire suite
from the DB. I do this by requiring nulldb and then setting the adapter
in my spec_helper.rb:

Turn DB off by default for specs

ActiveRecord::Base.establish_connection(:adapter => :nulldb)

This helps immensely because you can still use your regular AR objects
and you can even call #save and #create and get unique ids back. There
are some caveats and gotchas associated with the style but I think it is
well worth it. The largest caveat is that you can not do SELECTs. In a
way this has been very good for the design of my current project because
it forces me to use stubbing and push my custom finders in they own
methods on different classes/objects. Once I have isolated the finders
in their own methods then I turn on the regular db adapter to write
examples against for it. The fact that it is isolated though allows me
to test with a small dataset which generally is quite faster than the
other datasets that would of been needed in my examples that I stubbed
results for.

To turn my real database on for individual examples this is the code I
use:

unless Object.const_defined?(:Functional)
share_as :Functional do

  before :all do
    ActiveRecord::Base.establish_connection(:test)
  end

  after :all do
    ActiveRecord::Base.establish_connection(:adapter => :nulldb)
  end
end

end

Then in the example I say:

describe “when there are ten users in the database” do
include Functional

end

I have actually also implemented what you have suggested so I can also
say:

describe “when there are ten users in the database”, :functional => true
do

end

I was going to use that implementation to have the runner only run the
type of examples I want to at a given moment. However, I think I’m
going organize my examples by directories because that is already
supported in rspec. So, as Pat already mentioned, it would look
something like:

spec/
functional/
models/
object-level/
controllers/
models/

I should also say that in some of my cases I have not been doing any
functional examples. That is because I have been using Stories/Fearures
to drive the entire process so I just let them test my SQL against a
real DB when I’m not doing anything out of regular AR.

HTH,

Ben

On 23 Sep 2008, at 16:25, Joseph W. wrote:

Matt W. wrote:

So we’ve got a pretty decent number of specs now, and despite my
best efforts, AR is just forcing us down the path of having to use
database interaction for some of the model specs.
Just out of curiosity, I would be interested to know how AR is
forcing you to use database interaction in your model specs. Can
you give an example?

Well, mostly this is either where we’re doing complex manipulation of
object through associations, and I’m having to fake too much of the
AssociationProxy stuff to feel comfortable, or where people are
writing custom SQL to get control over the way joins are done.

I think we may be falling into the latter hole a bit too readily, and
we’ll have a review of it soon. It certainly doesn’t make it as easy
as other ORMs to forget about the database, though.

cheers,
Matt

http://blog.mattwynne.net

In case you wondered: The opinions expressed in this email are my own
and do not necessarily reflect the views of any former, current or
future employers of mine.

On Sep 23, 2008, at 11:49 AM, Pat M. wrote:

and making me worry about how things are going to be in a few
describe “when there are ten users in the database”, :slow => true do
controllers/
models/
unit/
controllers/
models/

Yeah - Bryan and I paired @ Eastmedia before he left for WePlay to
develop the following monkey patch to support that:

module Spec
module Example
class ExampleGroupFactory
# Used to support spec/unit and spec/integration
def self.determine_superclass(opts)
spec_path = opts[:spec_path].to_s.gsub("/spec/unit", “/spec”)

     id = if opts[:type]
       opts[:type]
     elsif spec_path =~ /spec\/integration\/routing_spec/
       :controller
     elsif spec_path =~ /spec\/integration/
       :model
     elsif spec_path =~ 

/spec(\|/)(#{@example_group_types.keys.join
(’|’)})/
$2 == ‘’ ? nil : $2.to_sym
end
get(id)
end
end
end
end

Hopefully someone will find this useful.

Scott

On 23 Sep 2008, at 16:49, Pat M. wrote:

spec/
integration/
controllers/
models/
unit/
controllers/
models/

Pat

Yeah, I think that is probably the easiest way to do it, I just don’t
like the idea of having the specs for a single class in two places.
But maybe that overhead would actually be the encouragement we need
to think a little bit harder about whether there’s a better way to
write the spec in the first place… :slight_smile:

cheers,
Matt

http://blog.mattwynne.net

In case you wondered: The opinions expressed in this email are my own
and do not necessarily reflect the views of any former, current or
future employers of mine.

On 23 Sep 2008, at 17:11, Ben M. wrote:

Then in the example I say:
true do

end

HTH,

That helps a huge amount. Can’t wait to have some time to dig into
this. Thanks Ben.

cheers,
Matt

http://blog.mattwynne.net

In case you wondered: The opinions expressed in this email are my own
and do not necessarily reflect the views of any former, current or
future employers of mine.