The problem with learning RSpec

I read this whole thread with interest (alerted by a cross-post on the
railsbridge list, thx Zach). Thanks Stephen for kicking off this
interesting discussion:

sample rails app that makes good use of RSpec and Cucumber. I think
BDD… It is something I would like to revisit someday and provide
such
an app. Have you started on a tutorial app like this yet?

I am very interested in understanding how to teach TDD/BDD. I learned
both as part of learning Rails. As an experienced programmer in other
languages it was really important to me to learn testing as I learned
this new language, since my motivation for learning was that I was
taking a job as a solo engineer on a legacy Rails 2.0.2 codebase. I
felt if I didn’t really understand testing, I was going to be in a
world of hurt. I also was just really excited about cucumber when I
first heard about it.

I decided to start learning BDD on day 3 of learning Rails and
documented my experience as a tutorial here:
http://www.ultrasaurus.com/sarahblog/2008/12/rails-2-day-3-behavior-driven-development/
http://www.ultrasaurus.com/sarahblog/2008/12/rails-2-day-4-rcov-and-more-behavior-driven-development/

Later I learned about RSpec and the out-of-the-box testing that comes
with Rails. I ended up hiring someone to work with me on the Rails
project since it ended up being a pretty big job and we used TDD as a
way to understand and document the codebase. Learning by doing with
pair programming was an awesome way to learn. We use Rspec mostly for
model testing and cucumber for integration (controller/view) testing.
We have a few specs for controller and views, but using cucumber at
the higher level seems to work very well.

Recently I taught a one-day workshop where I taught people who already
knew a different programming language how to program in Ruby on
Rails. I added in TDD in the afternoon and I think it worked really
well. (Note that we only got as far as model testing) I think it
worked well to scaffold first to introduce people to what a Rails app
“feels” like, then use testing as they add their own code.

I’ll be teaching the same class in August and look forward to fleshing
out the curriculum a bit more and seeing if I can get some feedback
afterwards on how it was for the students. The workshop is “open
source” and you can look at what we taught here:
http://wiki.devchix.com/index.php?title=Workshop_Topics
(see #Add_votes for where the TDD part starts. This is a work in
progress, and some of the notes are rough) In this workshop, I made
up the TDD part of the lesson on-the-fly with my pair-teacher since I
felt so strongly that it needed to be taught. Another teacher who
taught the class as it was originally written said that the adding
votes & associations section was hard to teach since you needed to
write so much code before you saw any results. The immediate feedback
of TDD makes it fun to teach.

As someone who recently learned Rails and Ruby, I feel strongly that
TDD/BDD should be learned right along with the rest of the framework.
While I do love RSpec, I’m not sure it should be taught first thing,
primarily since I think people should understand the parts that come
with, but it also feels like there is a lot of detailed APIs you need
to know. I do find it interesting that cucumber, which is a higher
level framework, doesn’t feel that way.

Sarah
http://www.ultrasaurus.com

Just to add a couple cents in…

I’ve been working as either a sysadmin or software developer for the
last 10 years (software development pretty much exclusively for the
last 5 or 6). I started picking up Rails about 2 years ago, and though
I was always aware of TDD - and even occasionally dabbled in it - I
never really embraced it. Not because I didn’t see its importance, but
because the barrier to entry always seemed too high, and schedules
never allowed for it (as a friend of mine is fond of saying, “You mean
we don’t have time to do it right, but we have time to do it over and
over again?”).

Right now I’m working on a personal project for which I have no QA
team to watch my back, so instead I’m doggedly using top-down BDD with
Cucumber (and unit tests) to help keep me in line. I think the biggest
hurdle to learning it is this: Pretty much all the tutorials and docs
written on the topic center around some simple example app that’s easy
to test. But in the real world, software is messy, and tends to resist
being tested. I know the traditional counter argument is that this
means your design is flawed, but that isn’t always true. One of the
biggest challenges I faced was how to test authentication in my
application, in which users sign in using their Twitter credentials
via OAuth[1]. Another was in testing my own endpoints that create JSON
that’s rendered via JS in the browser[2]. Maybe Selenium could have
helped here, but creating tests in general was already slowing me to
the point that I’m a good deal behind schedule, and I couldn’t take
another day or so to learn how to use Selenium with the risk that it
might not really suit my situation for one reason or another - because
software is messy.

One that I haven’t tackled yet but will have to soon is how to test
code that runs as a BackgrounDRb worker.

I came up with solutions for all of this (except for the BDRb stuff),
but I’m not entirely sure of their quality. They certainly feel
hackish, but I can’t put my finger on why. I suspect David C.
or Ben M. or Aslak or any of a hundred or more other people could
have come up with beautiful, elegant solutions to the challenges I
faced, but since none of them were standing over my shoulder I have no
way of knowing, and none of this is covered in the
write-a-blog-in-10-minutes Rails demo.

That has been my challenge in learning and using BDD.

[1] My solution: http://tr.im/oW8y
[2] I defined these two custom steps (JSON_CALLBACK is defined as the
:callback arg I pass in my ‘render :json’ calls - but it will trip the
JSON parser if its there):

Then /^I should get valid JSON$/ do
assert_nothing_raised do
assert JSON.parse(@response.body.gsub(/^#{JSON_CALLBACK}((.*))/,
‘\1’))
end
end

Then /^I should find “(.+)” in JSON/ do |xpath|
json_hash =
JSON.parse(@response.body.gsub(/^#{JSON_CALLBACK}((.*))/, ‘\1’))
xmldoc = Nokogiri::XML(json_hash.to_xml)
xpath.gsub!(‘_’, ‘-’) # in XML, underscores will be dashes.
xpath = “./hash” + xpath unless xpath =~ /^///
assert !xmldoc.xpath(xpath).blank?
end


Bill K.

http://bkocik.net

Bill K. wrote:

over again?").
application, in which users sign in using their Twitter credentials

I came up with solutions for all of this (except for the BDRb stuff),
but I’m not entirely sure of their quality. They certainly feel
hackish, but I can’t put my finger on why. I suspect David C.
or Ben M. or Aslak or any of a hundred or more other people could
have come up with beautiful, elegant solutions
I’m flattered, but FWIW I am always struggling on how best to test
things as well. In cases like you are describing it seems like testing
it is often harder than the actual implementation. Making those tests
valuable without being too brittle can be challenging.

to the challenges I
faced, but since none of them were standing over my shoulder I have no
way of knowing, and none of this is covered in the
write-a-blog-in-10-minutes Rails demo.

That has been my challenge in learning and using BDD.
Thanks for sharing Bill. I totally understand where you are coming
from. IME, it is hard when writing a tutorial or giving a presentation
to not teach to the least common denominator in the audience (the
beginner). Time constraints usually set in too that don’t allow you to
do more advanced topics that would require more explanation. Thats why
for most presentations I try to focus more on the process and ideas
rather than the example and tools (i.e stuff you can’t learn from a wiki
so easily). I do see your point however. I often feel frustrated in
other presentations at the simplicity of examples given and wish for
more in-depth and challenging examples. Your point is noted: a good
tutorial app for BDD should involve harder to test components (web
services, asynchronous messaging/processing, caching, etc) since this is
what pops up in real projects.

[1] My solution: http://tr.im/oW8y

This is more or less how I would of done this with Cucumber. And you
were complaining about no advanced tutorials. :wink: Nice writeup.

Then /^I should find “(.+)” in JSON/ do |xpath|
json_hash = JSON.parse(@response.body.gsub(/^#{JSON_CALLBACK}((.*))/, ‘\1’))
xmldoc = Nokogiri::XML(json_hash.to_xml)
xpath.gsub!(‘_’, ‘-’) # in XML, underscores will be dashes.
xpath = “./hash” + xpath unless xpath =~ /^///
assert !xmldoc.xpath(xpath).blank?
end

I probably would of done this in RSpec instead of Cucumber. Then I
would manually tested in a browser… since you are going to want to do
that anyways. I take this stance quite a bit as I feel adding Selenium
(or another automated browser solution) can potentially add much more of
a maintenance burden than webrat in :rails mode.

Thanks,
Ben

Thanks for the encouragement, Ben. :slight_smile:

On Thu, Jun 18, 2009 at 1:36 PM, Ben M. [email protected] wrote:

Then /^I should find “(.+)” in JSON/ do |xpath|
json_hash = JSON.parse(@response.body.gsub(/^#{JSON_CALLBACK}((.*))/, ‘\1’))
xmldoc = Nokogiri::XML(json_hash.to_xml)
xpath.gsub!(‘_’, ‘-’) # in XML, underscores will be dashes.
xpath = “./hash” + xpath unless xpath =~ /^///
assert !xmldoc.xpath(xpath).blank?
end

I probably would of done this in RSpec instead of Cucumber. Then I would manually tested in a browser… since you are going to want to do that anyways. I take this stance quite a bit as I feel adding Selenium (or another automated browser solution) can potentially add much more of a maintenance burden than webrat in :rails mode.

In this particular project, all the JS is written by my partner (I’m
completely JS-clueless). Having a bunch of lines in my cucumber tests
validating everything that should be in the JSON structure my
controllers generate in order for the JS to work (and I have a lot of
them) is the best way for me to be able to tell if I’ve broken
something (and if I have, in what way I broke it). If the page doesn’t
work, I will likely have difficulty figuring out why - unless Cucumber
is there to tell me it didn’t find “/response/statusCode” in the JSON
like it should have, then I know what to fix. :slight_smile:

Though I suppose there’s probably no reason RSpec couldn’t have done
the same thing. I haven’t used it yet in this project.


Bill K.

http://bkocik.net