[rspec-users] Dealing with dependent data

15 views
Skip to first unread message

Christopher Bailey

unread,
Jun 25, 2008, 2:37:04 PM6/25/08
to rspec-users
If there's already been a thread on this, let me know (and if you can,
point me to it)...

In building my stories, I often need to setup a bunch of data where
you have multiple levels of models that depend on each other. For
example, I'd have models like Doctor, Organization, and Location. To
run various scenarios that view doctors, say by organization, or by
tags, or whatever, I need to setup fixture-like data for locations,
then organizations (which belong to a location), then docs which
belong to an organization. I am sure others have this in their apps,
and I'm wondering how you organize you Given's/steps across these
things.

Right now, for example, I have doctor_steps, organization_steps, and
location_steps, which have their respective Givens in them. But,
what's been bugging me is that when one Given depends on another, the
only place this is really hinted at is in the plain text story file,
where I might have:

Scenario: view doctors
Given: existing locations
And: existing organizations
And: existing doctors

My steps that depend on other data always check for that existance.
e.g. in Organizations given, I'd do a "Location.count.should > 1" or
more specific depending on my needs, etc.

So, what are folks doing in this regard, any tips, recommendations,
suggestions, etc.? Is there some way to indicate dependencies like
this that I simply don't know about?

--
Christopher Bailey
Cobalt Edge LLC
http://cobaltedge.com
_______________________________________________
rspec-users mailing list
rspec...@rubyforge.org
http://rubyforge.org/mailman/listinfo/rspec-users

Mikel Lindsaar

unread,
Jun 25, 2008, 9:38:51 PM6/25/08
to rspec-users
On Thu, Jun 26, 2008 at 4:37 AM, Christopher Bailey
<ch...@cobaltedge.com> wrote:
> If there's already been a thread on this, let me know (and if you can,
> point me to it)...

I asked something similar about a week or so ago, you can see it here:

http://www.ruby-forum.com/topic/156392

It is on 'reusing story specs'

But I have done some more work since then...

> In building my stories, I often need to setup a bunch of data where
> you have multiple levels of models that depend on each other. For

> Scenario: view doctors


> Given: existing locations
> And: existing organizations
> And: existing doctors

You can use plain text stories and use multiple steps_for to get a
similar effect.

But in this case, on that set of stories, it would make sense to
reduce that Given block down to:

# viewing doctors story file...
Scenario: view doctors
Given: existing doctors in organizations that have a location
When...

And then I would use some helpers or fixture loading to handle your
data loading...

# spec helper file...
def build_valid_doctor(params)
location = Location.create(:blah...)
org = Organization.create(:location => location)
Doctor.create({:organization => org}.merge(params))
end

# steps file....
steps_for :viewing_doctors do

Given "existing doctors in organizations that have a location"
build_valid_doctor(:surname => 'Hyde')
build_valid_doctor(:surname => 'Jeckle')
end

end


Of course you can make those factory methods do all sorts of things...

Hope that helps

Mikel

--
http://lindsaar.net/
Rails, RSpec, Puppet andLife blog....

Scott Taylor

unread,
Jun 25, 2008, 10:07:39 PM6/25/08
to rspec-users


It really seems you are asking two questions: One about reusability,
and one about setting up data.

I can't add anything to the first, but factories are definitely the
way to go regarding the second issue (setting up the data). Check out
this post by Dan Manges (and look at the fixture options at the end of
the post):

http://www.dcmanges.com/blog/38

Scott

Christopher Bailey

unread,
Jun 25, 2008, 10:18:54 PM6/25/08
to rspec-users
In reply to both of the last two replies to my post...

I am already doing the factory stuff for data creation. My question
is more about dependencies between fixture data sets.

So, you have 3 related models: A, B, C. Model A can stand on its own.
Model B can't exist without an A, and C can't exist without a B
(which means it also indirectly requires an A). I have factories that
create these things, and helper methods that create sets of them
(since I need fairly specific relationships, not just randomly
generated ones like say object_daddy or factory_girl plugins/gems help
with (although I have used object_daddy and like it - tried to use
factory girl, but had problems).

It's not really a true "problem", it's more that there is an inherant
dependency here, where there isn't a very expressive way of stating
that. So, more a point of discussing how other folks are handling
this and making things clear in their code that their are
dependencies. The idea to combine the 3 givens is a point I'll look
at, as I think I agree that that probably conveys the dependency and
association between the three models better.

The other thing I'm finding a lot is that I have a lot of the same
needs for this fixture type data between my regular RSpec examples
(model tests mostly, as I'm going light on controller and view tests
and mostly doing stories) and my RSpec stories. Are folks using say a
single helper/factory to generate fixture data for both? I guess I
only just though of sharing it between them now, as there really is no
technological barrier to doing so, although in my examples I do tend
to leverage mocks and stubs when I can, but stay strictly "real" with
stories.

--

Christopher Bailey
Cobalt Edge LLC
http://cobaltedge.com

Mikel Lindsaar

unread,
Jun 25, 2008, 10:38:22 PM6/25/08
to rspec-users
On Thu, Jun 26, 2008 at 12:18 PM, Christopher Bailey
<ch...@cobaltedge.com> wrote:
> The other thing I'm finding a lot is that I have a lot of the same
> needs for this fixture type data between my regular RSpec examples
> (model tests mostly, as I'm going light on controller and view tests
> and mostly doing stories) and my RSpec stories. Are folks using say a
> single helper/factory to generate fixture data for both? I guess I
> only just though of sharing it between them now, as there really is no
> technological barrier to doing so, although in my examples I do tend
> to leverage mocks and stubs when I can, but stay strictly "real" with
> stories.

For me, I tend to use a Model.build_valid pattern to create objects
required in my controller view or model specs and then only really
stub required behaviour... sort of like cherry picking stubs.

So I wouldn't stub the 'name' method on a person, instead, I would
create a valid person with the name I need. But I would stub that
'save' returns 'true' or something of the like as I need to ensure a
particular execution path.

This arguably makes specs more brittle, but for me, finding and fixing
failed dependencies as soon as possible is better than having to
manually ensure that every method being called in a view is covered
elsewhere by a spec... and in changing a spec later, I get instant
feedback on if I have a regression failure elsewhere.

The other drawback you have with fixture data in stories is that they
are by definition an artificial state. It is not guaranteed that the
state you create with fixtures could be reproduced by your code. Only
through your code executing can you find the relevant states and you
might introduce an arbitrary in your fixture data that creates an
impossible state allowing your specs to pass.

So I ban fixtures in stories in my team for that reason. Anything you
need in a story needs to be encompassed in the Given of that story and
the story needs to be able to be read in isolation with all
requirements visible, see my blog post on "Being clever in specs is
for dummies" at

http://www.lindsaar.net/2008/6/24/tip-24-being-clever-in-specs-is-for-dummies

For more on what I mean about that, the example is mainly for a
describe BDD block, but it applies equally well to a story.

Regards

Christopher Bailey

unread,
Jun 25, 2008, 11:38:56 PM6/25/08
to rspec-users
I agree in general on fixtures, depending on how you define
"fixtures". I never use the standard Rails fixtures, or any YAML
based fixture data. I always generate my data from a factory or real
ActiveRecord call to create the object. But, I still consider this
essentially "fixture" data, it's just created a different way. It's a
trade-off. If in my stories I had to walk through the view and create
the 30+ objects I needed just to setup my test, well, that test just
might not get written. So to me, I use real ActiveRecord calls (via a
factory or helper of whatever kind), so that at least I know the model
creation is going through the real code, and is pretty close to the
path that the controller would do. Then I test whatever it is I'm
testing that needs to have data like that.

For tests of new/create views, I of course actually create the models
via the view (I use Webrat), and such, so that is definitely real, and
that to me covers that case sufficiently.

--

Christopher Bailey
Cobalt Edge LLC
http://cobaltedge.com

David Chelimsky

unread,
Jun 26, 2008, 9:48:01 AM6/26/08
to rspec-users
On Jun 25, 2008, at 9:38 PM, Mikel Lindsaar wrote:
> http://www.lindsaar.net/2008/6/24/tip-24-being-clever-in-specs-is-for-dummies

That post is fantastic. Thanks!

Bart Zonneveld

unread,
Jun 26, 2008, 11:25:27 AM6/26/08
to rspec-users

On 26-jun-2008, at 15:48, David Chelimsky wrote:

> On Jun 25, 2008, at 9:38 PM, Mikel Lindsaar wrote:
>> http://www.lindsaar.net/2008/6/24/tip-24-being-clever-in-specs-is-
>> for-dummies
>
> That post is fantastic. Thanks!

Couldn't agree more with that post... For instance,
restful_authentication now comes with specs, but, ehrm... See for
yourself: http://pastie.org/222670

gr,
bartz

Mikel Lindsaar

unread,
Jun 26, 2008, 7:55:39 PM6/26/08
to rspec-users
On Fri, Jun 27, 2008 at 1:25 AM, Bart Zonneveld <lo...@superinfinite.com> wrote:
> On 26-jun-2008, at 15:48, David Chelimsky wrote:
>> On Jun 25, 2008, at 9:38 PM, Mikel Lindsaar wrote:
>>> http://www.lindsaar.net/2008/6/24/tip-24-being-clever-in-specs-is-for-dummies
>> That post is fantastic. Thanks!
> Couldn't agree more with that post... For instance, restful_authentication

Thanks guys.

spread the word... I am sick of having to mentally translate
everything in specs :)

--
http://lindsaar.net/
Rails, RSpec, Puppet andLife blog....

Scott Taylor

unread,
Jun 26, 2008, 8:37:56 PM6/26/08
to rspec-users

On Jun 26, 2008, at 11:25 AM, Bart Zonneveld wrote:

>
> On 26-jun-2008, at 15:48, David Chelimsky wrote:
>
>> On Jun 25, 2008, at 9:38 PM, Mikel Lindsaar wrote:
>>> http://www.lindsaar.net/2008/6/24/tip-24-being-clever-in-specs-is-for-dummies
>>
>> That post is fantastic. Thanks!
>
> Couldn't agree more with that post... For instance,
> restful_authentication now comes with specs, but, ehrm... See for
> yourself: http://pastie.org/222670
>

haha. I have no idea what's going on there.

Ben Mabey

unread,
Jun 26, 2008, 9:52:03 PM6/26/08
to rspec-users
Scott Taylor wrote:
>
> On Jun 26, 2008, at 11:25 AM, Bart Zonneveld wrote:
>
>>
>> On 26-jun-2008, at 15:48, David Chelimsky wrote:
>>
>>> On Jun 25, 2008, at 9:38 PM, Mikel Lindsaar wrote:
>>>> http://www.lindsaar.net/2008/6/24/tip-24-being-clever-in-specs-is-for-dummies
>>>>
>>>
>>> That post is fantastic. Thanks!
>>
>> Couldn't agree more with that post... For instance,
>> restful_authentication now comes with specs, but, ehrm... See for
>> yourself: http://pastie.org/222670
>>
>
> haha. I have no idea what's going on there.
>
>

This is slightly OT.. but looking at those specs brings up one of my
other pet peeves, and that is excluding the "should" from the specs. I
have seen a lot of projects and developers that I respect highly not use
the word "should" in there specs. I have accepted it as just one of
those things that people disagree on, but I think there is a lot of
value of having the "should". For one it makes removing the example
easier when it becomes incorrect (meaning, the expected behaviour has
changed.) I guess I just see the "should" as being a bigger part of BDD
than some people.

Am I the only one who thinks this or what are the arguments for not
using 'should'?

-Ben

Jim Gay

unread,
Jun 27, 2008, 7:58:11 PM6/27/08
to rspec-users
>>>>> http://www.lindsaar.net/2008/6/24/tip-24-being-clever-in-specs-is-for-dummies
>>>>
>>>> That post is fantastic. Thanks!
>>>
>>> Couldn't agree more with that post... For instance,
>>> restful_authentication now comes with specs, but, ehrm... See for
>>> yourself: http://pastie.org/222670
>>
>> haha. I have no idea what's going on there.
>
> This is slightly OT.. but looking at those specs brings up one of my
> other pet peeves, and that is excluding the "should" from the
> specs. I have seen a lot of projects and developers that I respect
> highly not use the word "should" in there specs. I have accepted it
> as just one of those things that people disagree on, but I think
> there is a lot of value of having the "should". For one it makes
> removing the example easier when it becomes incorrect (meaning, the
> expected behaviour has changed.) I guess I just see the "should" as
> being a bigger part of BDD than some people.
>
> Am I the only one who thinks this or what are the arguments for not
> using 'should'?

I've been meaning to ask the list about this for a while now.

I don't always use "should", but I've been trying to come up with a
standard way to approach the Rails has_one, has_many, etc. as opposed
to methods on the object such as name, description etc.
What I mean is that I want to write specs so that I know if something
refers to an associated object or not, without resorting to writing
technically oriented specs that define implementation rather than
behavior.
"project should have an owner" unfortunately doesn't let me know if
it's a method that returns a value, or a method that returns another
object. Does anyone have advice or experience in writing the specs to
provide that kind of information?

I hope this isn't too much of a thread hijack.
But to bring it back around, I totally agree with the article, and
it's particularly apropos for open source projects (assuming the
project owner wants new users to get involved in development)

-Jim

David Chelimsky

unread,
Jun 27, 2008, 10:07:27 PM6/27/08
to rspec-users
On Jun 27, 2008, at 6:58 PM, Jim Gay wrote:

> I've been meaning to ask the list about this for a while now.
>
> I don't always use "should", but I've been trying to come up with a
> standard way to approach the Rails has_one, has_many, etc. as
> opposed to methods on the object such as name, description etc.
> What I mean is that I want to write specs so that I know if
> something refers to an associated object or not, without resorting
> to writing technically oriented specs that define implementation
> rather than behavior.
> "project should have an owner" unfortunately doesn't let me know if
> it's a method that returns a value, or a method that returns another
> object.

An association does not want you to know that it's an association. It
wants you to think of it as any other attribute. Why do you care what
it IS? Focus on what it DOES.

> Does anyone have advice or experience in writing the specs to
> provide that kind of information?
>
> I hope this isn't too much of a thread hijack.

We'll make a new thread then :)

My opinion is that attributes and associations are equally about
structure, not behaviour. The fact that a project has an owner is not
behaviour. The fact that the owner has an email address is not
behaviour.

The facts that you can't save a project without an owner, and you
can't save an owner without a valid email address are behaviour. And
by setting expectations around those, the attributes and associations
themselves are handled implicitly:

describe Project do
it "should not be valid without an owner" do
Project.new(:owner => nil).should_not be_valid
end
end

Watch that fail saying that Project does not respond to 'owner='
method. Add a migration and an association. Now it fails saying that
it was valid. Add the validation and watch the example pass. That's
TDD (yes, starting with a T).

Any time I have a an attribute or an association that I *think* is
supposed to be on a model, I try to think of what might be interesting
about that attribute or association and set expectations about that.

There are many who believe that we should have examples like
"project.should have_one(:owner)." I can't say that those people are
wrong if doing that is adding value to their process and helping them
deliver quality software. For me, personally, it's just unnecessary
noise that adds maintenance burden later when things move around. And
it definitely ain't behaviour.

Cheers,
David

Jim Gay

unread,
Jun 27, 2008, 10:55:49 PM6/27/08
to rspec-users
On Jun 27, 2008, at 10:07 PM, David Chelimsky wrote:
> An association does not want you to know that it's an association.
> It wants you to think of it as any other attribute. Why do you care
> what it IS? Focus on what it DOES.

Good point. Being a newbie I sometimes find myself where I *think* I'm
doing it well, but find out that it's not quite that good afterall.

Thanks for the response. Perhaps I'm over thinking things. I agree
that "project.should have_one(:owner)" is unnecessary.

Somewhere the ideas get mangled for me.
Suppose a simple spec like this:

Project "should not be valid without a name"
Owner "should not be valid without a name"

How do you spec that the Owner may have 0 or more projects?

Owner "should be valid with 0 projects"
Owner "should be valid with more than 0 projects"

Or would you combine them

Owner "should have 0 or more projects"

Or should I not care at all about that and just specify that a Project
"should not be valid without an owner"?

David Chelimsky

unread,
Jun 28, 2008, 5:32:07 AM6/28/08
to rspec-users
On Jun 27, 2008, at 9:55 PM, Jim Gay wrote:

> On Jun 27, 2008, at 10:07 PM, David Chelimsky wrote:
>> An association does not want you to know that it's an association.
>> It wants you to think of it as any other attribute. Why do you care
>> what it IS? Focus on what it DOES.
>
> Good point. Being a newbie I sometimes find myself where I *think*
> I'm doing it well, but find out that it's not quite that good
> afterall.

There's a great bit of advice in The Inner Game of Tennis that
suggests that judging your progress with statements like "I'm doing
well" or "I'm doing badly" is counter-productive; that it's more
productive to think in terms of observing whether your actions get you
to your goal and adjusting based on your observations.

You're doing fine.

Again, structure. Why do you care? Does an owner behave differently if
there are 0 projects or more than 0? Is there a maximum number of
projects? Maybe projects should be tagged and you want to be able to
get an owner's projects by tag? Now THAT's interesting behaviour that
you can write examples for.

> Owner "should be valid with 0 projects"
> Owner "should be valid with more than 0 projects"
>
> Or would you combine them
>
> Owner "should have 0 or more projects"
>
> Or should I not care at all about that and just specify that a
> Project "should not be valid without an owner"?

I'm beginning to regret the validity example, because it is somewhat
structural as well. The behaviour is not whether it's valid or not,
but rather whether you can save it or not. So scratch the example I
gave earlier and think about this:

describe Project do
describe "when trying to save" do
it "should complain if it has no owner" do
lambda do
Project.new(:owner => nil).save!
end.should raise_error(ActiveRecord::RecordInvalid)
end
end
end

(Zach Dennis - this nesting structure should make you happy :) )

That make a bit more sense?

One key aspect of BDD is working Outside-In. I try to start with a
story and to drive things down from the view to the model (in Rails).
So maybe my story is that as an owner I can edit my projects, but not
other people's projects. This is going to naturally lead me towards
examples that will implicitly cover the fact that an owner can more
than 0 projects without actually specifying that directly.

HTH,
David

Jim Gay

unread,
Jun 28, 2008, 9:52:17 AM6/28/08
to rspec-users

On Jun 28, 2008, at 5:32 AM, David Chelimsky wrote:
> I'm beginning to regret the validity example, because it is somewhat
> structural as well. The behaviour is not whether it's valid or not,
> but rather whether you can save it or not. So scratch the example I
> gave earlier and think about this:
>
> describe Project do
> describe "when trying to save" do
> it "should complain if it has no owner" do
> lambda do
> Project.new(:owner => nil).save!
> end.should raise_error(ActiveRecord::RecordInvalid)
> end
> end
> end
>
> (Zach Dennis - this nesting structure should make you happy :) )
>
> That make a bit more sense?

Absolutely!

> One key aspect of BDD is working Outside-In. I try to start with a
> story and to drive things down from the view to the model (in
> Rails). So maybe my story is that as an owner I can edit my
> projects, but not other people's projects. This is going to
> naturally lead me towards examples that will implicitly cover the
> fact that an owner can more than 0 projects without actually
> specifying that directly.

Trying to wrap my head around how to go about BDD has been difficult
and I think I now understand why. Many of the examples I've seen for
RSpec have used things like "should be valid" when that doesn't
actually describe behavior at all. The first RSpec generated Rails
specs that I used had plenty of this but that seems to be more about
implementation than behavior, so I've had trouble understanding how to
really describe behavior.

Little by little I'm getting it, but I unfortunately don't feel like I
have time to go BDD cold turkey. I still do some code first and then
spec, but I understand the benefits of BDD and I'm sure I'll get to
that point eventually.

David Chelimsky

unread,
Jun 28, 2008, 10:34:43 AM6/28/08
to rspec-users

Ugh! You're right. I'm going to review the generators (they were
written a lot of water-under-the-bridge-ago).

> ... but that seems to be more about implementation than behavior, so

> I've had trouble understanding how to really describe behavior.
>
> Little by little I'm getting it, but I unfortunately don't feel like
> I have time to go BDD cold turkey. I still do some code first and
> then spec, but I understand the benefits of BDD and I'm sure I'll
> get to that point eventually.

Try this as a next step:

* code a little
* comment out your code
* write a small example for a small bit of the commented code
* watch it fail
* uncomment just enough to make it pass
* watch it pass
* repeat the last 4 steps

This is NOT the end-game, but it will give you a feel for the TDD
flow. Plus, at some level, we're all usually operating with some
knowledge about the code we're going to write. When we're not, it's
common practice from old-school-TDD to code a little, throw out the
code entirely (not comment it, but actually delete it) and then start
w/ examples. The reason we throw it out is the "code a little" phase
quite often introduces something we just don't need. In the comment/
uncomment approach, those unnecessary bits tend to stick around
because we *think* we need them.

One great promise of TDD is that it encourages less code because we're
working against executable examples rather than assumptions about what
the code does based on looking at it.

Cheers,
David

Reply all
Reply to author
Forward
0 new messages