Newbie cucumber tutorial


#1

I got started with cucumber and it sure is fun. I’ve written up my
initial experience in tutorial format here for any newbies who want to
follow in my tracks:
http://www.ultrasaurus.com/code/2008/12/rails-2-day-3.html

If anyone has any corrections, let me know. I was wondering whether
when writing a real application, do you usually write your whole spec
with lots of scenarios at once and then get them the execute one at a
time? or do you write and code one scenario at a time?

Thanks,
Sarah

p.s. what is the relationship between cucumber and RSpec?


#2

Great stuff.

One thing I’d point out is the missing (and extremely important) step
3.5 in Rick Denatale’s TDD steps: Refactor to remove duplication.

Not that there’s any refactoring necessary in your example, but it’s
always worth reminding people they should check for it.

On 22 Dec 2008, at 09:01, Sarah A. wrote:

I got started with cucumber and it sure is fun. I’ve written up my
initial experience in tutorial format here for any newbies who want to
follow in my tracks:
http://www.ultrasaurus.com/code/2008/12/rails-2-day-3.html

If anyone has any corrections, let me know. I was wondering whether
when writing a real application, do you usually write your whole spec
with lots of scenarios at once and then get them the execute one at a
time? or do you write and code one scenario at a time?

Mostly I pick off a simple scenario, write it into Cucumber, then dive
into the code to make it work. Then when I’m back on the surface with
the scenario passing, I think about the next simplest scenario, write
that up into a feature, and I’m off again.

Sometimes I keep a list (you can use # to comment lines in
the .feature file) of scenarios I’m going to write up later, so I have
a kind of ‘todo list’ but I don’t usually flesh them out into
executable scenarios with steps until I’m ready to work on them.

p.s. what is the relationship between cucumber and RSpec?

Short version: RSpec is for unit testing, Cucumber is for acceptance
testing.

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


#3

Aslak Hellesøy wrote:

  • I released 0.1.13 yesterday. In the Rails installation wiki page I
    recommend using my webrat gem. It lets you use response.should
    have_selector(…) (You’re not using it in your tutorial, but just in
    case…)

Luckily I started with cucumber on Sunday just after your release, so
I’m using that version. What does have_selector do? (Is there an API
reference somewhere that I missed?)

  • “Write a Spec” should be “Write a feature” (specs is confusing here
    because that is what people use RSpec for. describe and it style). There
    are
    some other refs to “spec” which should be “feature”.

I changed it to “describe a feature,” since to me “write a feature”
means writing the code. When I started using cucumber, I thought it was
part of RSpec. The cucumber .feature files still feel like a spec to me
and since I’ve never used RSpec, I don’t really appreciate the
distinction.

  • Use bang! methods when creating records. Otherwise a failure to create
    will silently pass without you knowing. Example:

task = Task.new(:description => desc) # Lose the semicolon
task.save!

Or simpler:
Task.create!(:description => desc)

Thanks for the tip. As you can see from my series of blog posts, I’m
new to Ruby and Rails. I thought that ending a method with ! was a
naming convention. Reading the humble ruby book it says “Another
convention to follow is that if the method modifies its receiver in
place (i.e. the method modifies the object that called it), then it
should end in an exclamation point” and the Rails doc show examples of
create without !
http://api.rubyonrails.org/classes/ActiveRecord/Base.html#M001969 but if
I make the change you suggest the test passes. I’ve updated the
tutorial and my code, but I’m confused.

Fun stuff. Thanks for making this!

Sarah


#4

On Mon, Dec 22, 2008 at 10:01 AM, Sarah A. removed_email_address@domain.invalid
wrote:

I got started with cucumber and it sure is fun. I’ve written up my
initial experience in tutorial format here for any newbies who want to
follow in my tracks:
http://www.ultrasaurus.com/code/2008/12/rails-2-day-3.html

If anyone has any corrections, let me know. I was wondering whether
when writing a real application, do you usually write your whole spec
with lots of scenarios at once and then get them the execute one at a
time? or do you write and code one scenario at a time?

Hi Sarah,

Thanks for the great writeup. It is simple to follow and explains what’s
going on really well. I have a few comments:

  • I released 0.1.13 yesterday. In the Rails installation wiki page I
    recommend using my webrat gem. It lets you use response.should
    have_selector(…) (You’re not using it in your tutorial, but just in
    case…)
  • “Write a Spec” should be “Write a feature” (specs is confusing here
    because that is what people use RSpec for. describe and it style). There
    are
    some other refs to “spec” which should be “feature”.
  • Use bang! methods when creating records. Otherwise a failure to create
    will silently pass without you knowing. Example:

task = Task.new(:description => desc) # Lose the semicolon
task.save!

Or simpler:
Task.create!(:description => desc)

Cheers,
Aslak


#5

On Mon, Dec 22, 2008 at 5:59 PM, Sarah A. removed_email_address@domain.invalid
wrote:

Aslak Hellesøy wrote:

  • I released 0.1.13 yesterday. In the Rails installation wiki page I
    recommend using my webrat gem. It lets you use response.should
    have_selector(…) (You’re not using it in your tutorial, but just in
    case…)

Luckily I started with cucumber on Sunday just after your release, so
I’m using that version. What does have_selector do? (Is there an API
reference somewhere that I missed?)

That’s part of the WebRat API:
http://gitrdoc.com/brynary/webrat/tree/master/

  • “Write a Spec” should be “Write a feature” (specs is confusing here
    because that is what people use RSpec for. describe and it style). There
    are
    some other refs to “spec” which should be “feature”.

I changed it to “describe a feature,” since to me “write a feature”
means writing the code.

“Cucumber Feature Description” is probably a better term.

When I started using cucumber, I thought it was
part of RSpec.

It’s not part of RSpec, but grew out of it.

The cucumber .feature files still feel like a spec to me
and since I’ve never used RSpec, I don’t really appreciate the
distinction.

They are two different projects. RSpec is for lower levels (objects). A
“test” in RSpec is called a spec. A “test” in Cucumber is called a
Feature.

Thanks for the tip. As you can see from my series of blog posts, I’m
new to Ruby and Rails. I thought that ending a method with ! was a
naming convention. Reading the humble ruby book it says “Another
convention to follow is that if the method modifies its receiver in
place (i.e. the method modifies the object that called it), then it
should end in an exclamation point” and the Rails doc show examples of
create without !
http://api.rubyonrails.org/classes/ActiveRecord/Base.html#M001969 but if
I make the change you suggest the test passes. I’ve updated the
tutorial and my code, but I’m confused.

The #create! method is documented here:
http://api.rubyonrails.org/classes/ActiveRecord/Validations/ClassMethods.html#M001902

Essentially, #create will never raise an error no matter what you pass
it,
and you actually want exceptions for bad input in your tests (step
definitions).
Therefore - use #create! (or #save!). In your app, use the non-bang
methods.

Cheers,
Aslak


#6

I realize this is off-topic for the RSpec forum and cucumber tutorial,
but I’m hoping you’ll enlighten me on this point which is, I guess, more
of a Ruby language question…

Aslak Hellesøy wrote:

As you can see from my series of blog posts, I’m
new to Ruby and Rails. I thought that ending a method with ! was a
naming convention. Reading the humble ruby book it says “Another
convention to follow is that if the method modifies its receiver in
place (i.e. the method modifies the object that called it), then it
should end in an exclamation point” and the Rails doc show examples of
create without !
http://api.rubyonrails.org/classes/ActiveRecord/Base.html#M001969 but if
I make the change you suggest the test passes. I’ve updated the
tutorial and my code, but I’m confused.

The #create! method is documented here:
http://api.rubyonrails.org/classes/ActiveRecord/Validations/ClassMethods.html#M001902

Essentially, #create will never raise an error no matter what you pass
it,
and you actually want exceptions for bad input in your tests (step
definitions).
Therefore - use #create! (or #save!). In your app, use the non-bang
methods.

My Task model is simply defined (by the generate scaffold script) as:
class Task < ActiveRecord::Base
end

How is it that I can call Task.create! which is a method of
ActiveRecord::Validations ?

Thanks in advance,
Sarah


#7

On Mon, Dec 22, 2008 at 8:09 PM, Sarah A. removed_email_address@domain.invalid
wrote:

should end in an exclamation point" and the Rails doc show examples of

How is it that I can call Task.create! which is a method of
ActiveRecord::Validations ?

Because ActiveRecord::Base includes the ActiveRecord::Validations
module.
It’s not clear from the RDoc though…

From active_record.rb:

ActiveRecord::Base.class_eval do
extend ActiveRecord::QueryCache
include ActiveRecord::Validations
include ActiveRecord::Locking::Optimistic
include ActiveRecord::Locking::Pessimistic
…lots more

Aslak


#8

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


#9

On Mon, Dec 22, 2008 at 11:29 AM, Caius D. removed_email_address@domain.invalid
wrote:

rescue_from handlers or within the controller actions themselves.
rspec-users mailing list
removed_email_address@domain.invalid
http://rubyforge.org/mailman/listinfo/rspec-users

I’m a “use the non-bang methods in the app, bang methods in tests”
guy. In the app, I don’t want an exception to be raised, because
validation failures aren’t exceptional. if @post.save is good enough
to know what happened. In tests though, I want it to fail fast and
noisily, so I use bang methods.

Pat


#10

+1 @ Pat

I was going to respond in more detail, but I do exactly what Pat does –
bang in steps, no bang in Rails apps. The Rails scaffolding boiler
plate
generates no bangs.
Steve


#11

On 22 Dec 2008, at 22:57, Sarah A. wrote:

Oddly, I didn’t see any content to the post by Caius D. via
ruby-forum (
http://www.ruby-forum.com/topic/174015?reply_to=762550#762530 )

How weird, wonder if its because I signed the email with my GPG key.
Have sent this one unsigned so lets see if the content shows up for
this one…

C

Caius D.
removed_email_address@domain.invalid
+44 (0) 7960 268 100
http://caius.name/


#12

You guys are awesome. For posterity, I’ve written up a bit about the
bang vs. non-bang as an aside in the tutorial:
http://www.ultrasaurus.com/code/2008/12/rails-2-day-3.html#syntax

I’ll have to read up on modules. (I’ve only just finished ch 3 of the
humble ruby book.)

Oddly, I didn’t see any content to the post by Caius D. via
ruby-forum (
http://www.ruby-forum.com/topic/174015?reply_to=762550#762530 )

Warm regards and happy thank yous,
Sarah


#13

On 22 Dec 2008, at 19:09, Sarah A. wrote:

ActiveRecord::Validations ?
ActiveRecord::Validations uses a trick that’s used widely in rails,
and is arguably[1] becoming a Ruby idiom, apparently.

This is the interesting bit, around line #275:

 def self.included(base) # :nodoc:
   base.extend ClassMethods

So basically that means that when the class ActiveRecord::Base
includes the module ActiveRecord::Validations, that module extends the
thing which included it (in this case ActiveRecord::Base) with the
class methods defined in ActiveRecords::Validations::ClassMethods.

Does that make sense?

I highly recommend reading David A Black’s ‘Ruby for Rails’ at this
point in your learnings. It did me a world of good when I was
similarly new to Ruby. It’s a really good deep grounding in Ruby IMO.

[1]http://blog.jayfields.com/2006/12/ruby-instance-and-class-methods-from.html

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


#14

Very nice indeed…

In your blog you said:

“Note that one of the steps is already defined in webrat. Isn’t that
cool? As you get the hang of this, you reuse certain word patterns
which map to specific tests. But we’re getting ahead of ourselves. We
need to dive into the creation of “steps” which make up our executable
spec. Cucumber gives a some handy snippets to get us started (in the
output of “rake features” above). We’ll paste these into a new file
that we’ll create in the “features/step_definitions” directory”

Why did one of the steps already get defined in webrat? Does it parse
“see” as indicative of UI? or what…?

Thanks very much.

Tim


#15

On Wed, Dec 24, 2008 at 12:10 AM, Tim W. removed_email_address@domain.invalid wrote:

output of “rake features” above). We’ll paste these into a new file
that we’ll create in the “features/step_definitions” directory"

Why did one of the steps already get defined in webrat? Does it parse
“see” as indicative of UI? or what…?

I try to only use magic when reality doesn’t work :wink:
When you run “script/generate cucumber” you get a webrat_steps.rb file
that
contains these common steps.

Aslak


#16

Ahh…reality is overrated.

Thanks again for your help guys. Making a lot of sense. If I could get
rcumber working that’s be awesome.

Tim

On Tue, Dec 23, 2008 at 4:39 PM, aslak hellesoy


#17

On 23 Dec 2008, at 18:26, Sarah A. wrote:

includes the module ActiveRecord::Validations, that module extends
http://dev.rubyonrails.org/browser/branches/2-0-stable/activerecord/lib/active_record/base.rb
Try here:
http://dev.rubyonrails.org/browser/branches/2-0-stable/activerecord/lib/active_record.rb
On line 42: require ‘active_record/validations’

If I assume that I’m looking at the wrong code or it happens thru some
magic then you can make a module which will add its class methods to
the

class which includes it?

I believe that’s how modules work, but it’s not by magic. If I’m
reading this Ruby book (by the Pragmatic Programmer’s) here correctly
then Ruby creates a singleton class of the object calling extend
(which I think is the reasoning behind the code referenced by Matt),
then includes the module into that singleton class, which adds the
instance methods of the module into the superclass chain for that
object’s class.

Is that some kind of trick to create multiple
inheritance? Is there any way without digging thru source to know
which
class include methods from other classes or do y’all just get so cozy
with every Rails class you use that you “just know?”

The Ruby classes Module and Object have some methods to determine
other included modules, available public|private|protected methods,
etc. if that helps.

Perhaps someone more experienced can fill in any gaps I may’ve missed

  • just happened to be reading about this myself…

Jeremiah


#18

On 23 Dec 2008, at 23:07, Jeremiah Heller wrote:

ActiveRecord::Validations, but I don’t see that in the code I’m
looking
at here:
http://dev.rubyonrails.org/browser/branches/2-0-stable/activerecord/lib/active_record/base.rb

Try here: http://dev.rubyonrails.org/browser/branches/2-0-stable/activerecord/lib/active_record.rb
On line 42: require ‘active_record/validations’

oops… line 59 looks useful as well: include ActiveRecord::Validations


#19

Matt W. wrote:

ActiveRecord::Validations uses a trick that’s used widely in rails,
and is arguably[1] becoming a Ruby idiom, apparently.

This is the interesting bit, around line #275:

 def self.included(base) # :nodoc:
   base.extend ClassMethods

So basically that means that when the class ActiveRecord::Base
includes the module ActiveRecord::Validations, that module extends the
thing which included it (in this case ActiveRecord::Base) with the
class methods defined in ActiveRecords::Validations::ClassMethods.

Does that make sense?

um, no. You say that the class ActiveRecord::Base includes the module
ActiveRecord::Validations, but I don’t see that in the code I’m looking
at here:
http://dev.rubyonrails.org/browser/branches/2-0-stable/activerecord/lib/active_record/base.rb

If I assume that I’m looking at the wrong code or it happens thru some
magic then you can make a module which will add its class methods to the
class which includes it? Is that some kind of trick to create multiple
inheritance? Is there any way without digging thru source to know which
class include methods from other classes or do y’all just get so cozy
with every Rails class you use that you “just know?”

I highly recommend reading David A Black’s ‘Ruby for Rails’ at this
point in your learnings. It did me a world of good when I was
similarly new to Ruby. It’s a really good deep grounding in Ruby IMO.

Just ordered a second-hand copy online. Thanks for the recommendation.

[1]http://blog.jayfields.com/2006/12/ruby-instance-and-class-methods-from.html
Nice reference, but I didn’t fully follow that either and posted a
similar question there.

Sarah

p.s Good question Tim on the webrat magic. I added a note to the
tutorial that explains where the step was defined.


#20

On 24 Dec 2008, at 02:26, Sarah A. wrote:

includes the module ActiveRecord::Validations, that module extends
http://dev.rubyonrails.org/browser/branches/2-0-stable/activerecord/lib/active_record/base.rb
You almost got it. Try here instead:
http://dev.rubyonrails.org/browser/branches/2-0-stable/activerecord/lib/active_record.rb

If I assume that I’m looking at the wrong code or it happens thru some
magic then you can make a module which will add its class methods to
the
class which includes it?

Yes, that’s basically what the self.included trick does. As I say,
it’s debatable whether this is a neat trick or a horrible hack. If you
were reading the code that included the module,. might have only
expected that would add instance methods, rather than class methods as
well.

Is that some kind of trick to create multiple
inheritance?

Not really in that particular case. Ruby modules generally allow you
to do multiple inheritance by ‘mixing in’ behaviour to classes, but
that would be when you use ‘include’ to bring the methods defined in
the module into the class itself.

Is there any way without digging thru source to know which
class include methods from other classes or do y’all just get so cozy
with every Rails class you use that you “just know?”

If you have hold of a class in ruby, there are ways to ask it what
modules / classes it inherits from, but I can’t remember them off the
top of my head, sorry. Try messing around in irb for this kind of thing.

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