Sample App - TDD with Cucumber and RSpec


#1

Hi,

I just posted a tiny app that I put together for a presentation on
Cucumber.

This essentially mirrors the workflow that I strive towards. (The README
explains more.) I don’t want to put myself out there as the standard to
immitate, but I think it will be helpful for people just getting started
with TDD/Cucumber/RSpec.

I’d really appreciate your feedback!

Paul

P.S. Sorry to the guys on IRC who got this message twice.


#2

Paul,

thanks for sharing your examples. I was just thinking about posting
something that can be introduced nicely with your sample app.

Now in cuc_demo we’ve got a step definition for /^there are no posties$/
in postie_steps.rb. This way, if we’d need to add a “Given there are no
users” step we should create a user_steps.rb with a similar definition.

IMHO it would be nice to have instead a “context_definitions.rb” with
common “givens” (similar to navigation_definitions.rb) and there a more
general definition, like for instance:

Given /^there are no (.*)$/ do |thing| thing_to_model(thing).destroy_all
end

In our World we should have a thing_to_class method with the mappings
between the names used in features and the model class that implement
them.

I think this mapping is also useful if tomorrow you and/or your client
decides to call it “pasties” instead of “posties” (and is more than
useful if you’re writing your features in other language than English,
cause you cannot obtain the class name through transformations of the
original “thing”).

Cheers,
nando

Pau C.
escribió:> Hi,

I’d really appreciate your feedback!

Paul

P.S. Sorry to the guys on IRC who got this message twice.


Fernando García Samblas
removed_email_address@domain.invalid

The Cocktail
C/ Salamanca 17
28020 Madrid
+34 91 567 06 05


#3

On 1 Dec 2008, at 19:00, Fernando García Samblas wrote:

users" step we should create a user_steps.rb with a similar

In our World we should have a thing_to_class method with the mappings
between the names used in features and the model class that
implement them.

I think this mapping is also useful if tomorrow you and/or your client
decides to call it “pasties” instead of “posties” (and is more than
useful if you’re writing your features in other language than English,
cause you cannot obtain the class name through transformations of the
original “thing”).

We have a convention here at Songkick (after a great deal of debate)
that it’s OK to refer to key domain concepts like Concerts, Artists,
Venues etc by their Ruby class name from within the scenario. Thus our
thing_to_model function is always a matter of just calling
thing.constantize.

I greatly prefer this to having any kind of custom mapping - it
promotes the ‘ubiquitous language’ that Eric Evans talks about in the
original DDD book.

Maybe it’s different when you’re working in another language though -
I guess it’s preferable to use English names for classes etc, is it?

Matt W.
http://blog.mattwynne.net
http://www.songkick.com


#4

Fernando García Samblas wrote:

IMHO it would be nice to have instead a “context_definitions.rb” with
common “givens” (similar to navigation_definitions.rb) and there a more
general definition, like for instance:

Given /^there are no (.*)$/ do |thing|

I really like that. It will make it much more clear since “Given there
are no” will be a very common step.

Paul


#5

On 2 Dec 2008, at 08:04, Pau C. wrote:

Given /^there are no (.*)$/ do |thing|

I really like that. It will make it much more clear since “Given there
are no” will be a very common step.

Hmmm, I personally think it’s safer to set up each scenario from a
blank slate. I’ve used “Given there are no X” steps before, but they
are just stubs to make the scenario read right, ie they simply don’t
create anything, rather than destroying existing data.

The current implementation,
Given /^there are no posties$/ do
Postie.destroy_all
end

strikes me more of a when step, eg
When /^all posties are destroyed$/ do
Postie.destroy_all
end

A Before block to destroy the Posties (and any other models) will
probably reduce issues in the long run if Postie began to depend on
another object, and was trapped by a database constraint.

Ashley


http://www.patchspace.co.uk/


#6

Ashley M. removed_email_address@domain.invalid writes:

create anything, rather than destroying existing data.

A Before block to destroy the Posties (and any other models) will
probably reduce issues in the long run if Postie began to depend on
another object, and was trapped by a database constraint.

Ashley

I’m with you on this. In fact, I think my implementation would be

Given …
Postie.count.should == 0
end

It’s just an assertion (in the C sense of the word, not testing). You
should be starting off with a clean slate anyway…but having a couple
assertions before you run can be very helpful for localization. Plus
this step can obviously be reused as a When.

Pat


#7

Matt W.
escribió:> Maybe it’s different when you’re working in another language though -

I guess it’s preferable to use English names for classes etc, is it?

Exactly Matt that’s it. I forgot to explain that, thanks for mention it.

We use pure English in our code and Spanish in the features.

A business term in Spanish can have a bunch of possible translations to
English. The mapping functions let us now exactly what are we talking
about, reducing ambiguity and improving communication with business
people.

Matt W.
http://blog.mattwynne.net
http://www.songkick.com


rspec-users mailing list
removed_email_address@domain.invalid
http://rubyforge.org/mailman/listinfo/rspec-users


Fernando García Samblas
removed_email_address@domain.invalid
http://nando.lacoctelera.com

The Cocktail
C/ Salamanca 17
28020 Madrid
+34 91 567 06 05


#8

On 2 Dec 2008, at 19:25, Pat M. wrote:

Given …
Postie.count.should == 0
end

It’s just an assertion (in the C sense of the word, not testing). You
should be starting off with a clean slate anyway…but having a couple
assertions before you run can be very helpful for localization. Plus
this step can obviously be reused as a When.

Nice idea! That kind of sanity checking can’t hurt.

Ashley


http://www.patchspace.co.uk/


#9

Ashley M.
escribió:> are just stubs to make the scenario read right, ie they simply don’t

create anything, rather than destroying existing data.

Yes, I also agree with you and Pat. Givens should create the scenario
context, not clean the garbage left by others.

But I was using it just as an example of “reusing” common Givens (after
all it was the only Given in Paul’s example app), the same way we do
with Whens a Thens.

Take this example instead:

Given /^there is (?:a|an) (.*)$/ do |thing|
@resources ||= []
@resources << thing_to_model(thing).create
end

Using a model factory like FixturesReplacement you can deal with
required data. WDYT?

A Before block to destroy the Posties (and any other models) will
probably reduce issues in the long run if Postie began to depend on
another object, and was trapped by a database constraint.

Ashley


Fernando García Samblas
removed_email_address@domain.invalid
http://nando.lacoctelera.com

The Cocktail
C/ Salamanca 17
28020 Madrid
+34 91 567 06 05