Am I speccing it wrong?

I consider myself an intermediate-to-advanced rubyist and rails
programmer. I’ve embraced TDD but sometimes wonder if I’m just doing
it wrong. I feel like it can take me longer to get the specs done
then should be necessary.

I’ll give a very specific example from a project I was working on last
night. I was working on a feature in a personal budget-management
application to be able to deposit and withdraw funds from/to an
‘account’.

I wrote a request/integration spec using capybara to go through the
interaction from a browser’s point of view - I went through every
possibility:

If a user deposits funds, the new amount should be displayed for the
account
If a user withdraws funds:
If there are enough funds remaining show the new amount
If there are not enough funds only allow the amount field to become
negative if the negative_overflow_id is the account itself (show the
new amount)
If there are not enough funds and the negative_overflow_id is
another account, remove the remaining amount from that account and
display the new amounts on both this account and the other account.
If there are not enough funds and no negative_overflow_id is set,
return an error on the field to the user indicating the problem.

This part I’m ok with, I think there should always be a walkthrough of
the full process that takes the entire stack into account. Since I’m
somewhat thorough in my request specs, I tend to skip view tests and
most of the controller tests (I’ll throw in some controller tests for
certain cases) because all of them together just take an inordinate
amount of time to finish.

I run the tests, I get red. I throw together the view and controller
enough so that the tests give me this error:

undefined method update_amount on Account

My controller is thin, and the view is simple. One field (amount)
with two submit buttons (“Withdraw” and “Deposit”). The controller
does this:

if @account.update_amount(params[:account][:amount], params[:commit])

All is well in the world. Now I drop down to model specs. I write
all of the expected cases for the model first before even defining the
method. (Is this how you’re supposed to do it?

My Account model spec ends up having 27 assertions (27 separate it
“should” blocks, mind you - I’ve joined the ‘don’t put multiple
assertions in one it block’ camp) for this one method.

The method appears that it is going to attempt to do too much, and I’m
very aware of this as I’m writing the specs. But I want to have the
‘end result’ mapped out before I write up the method.

My method, when all is said and done, ends up looking like this:

To implement the edge cases defined above I setup some before
validation and before update filters. My spec for the method passes,
so I know it’s doing what I want (in some fashion), but as I was
writing the code to make it work I failed to write any specs for the
callbacks that the model makes to implement the functionality.

I’m not sure what path I should have taken instead. Some camps seem
to think that you should stub off and use .should_receive calls for
specific behavior in a tested method to keep it isolated… but then
how do you really know that it’s adhering to the other methods’
parameters and such? Also if you do that, aren’t you mocking up
implementation in your spec which your test shouldn’t care about at
all (only the end result).

Should I keep this test with it’s 27 assertions, and then write
another 20 or so for all of the callback methods that help to
implement it’s behavior? It takes so long to get the request specs
and method specs written and then I end up having to re-write many of
them because of how I implemented the method.

Does anyone have thoughts on how this is supposed to be done in a TDD
fashion?

On May 4, 2011, at 5:25 PM, nbenes wrote:

I wrote a request/integration spec using capybara to go through the
If there are not enough funds and the negative_overflow_id is
amount of time to finish.

I run the tests, I get red.

If this is the first time you ran the specs and you have 6 failing
request specs, then this is not TDD. The idea of TDD is that you write
one example, and maybe not the whole example - just enough of an example
to get red - and then write just enough implementation code to change
the message or make it pass.

http://teachmetocode.com/articles/8-lessons-from-corey-haines-performance-kata/
http://aac2009.confreaks.com/07-feb-2009-13-30-tatft-the-laymans-guide-bryan-liles.html

Once passing, you look for refactoring opportunities in both the code
and spec. When you first start this, there isn’t much to refactor yet,
so you probably just skip to the next step: either add more to that
example (if it is not complete yet) or move on to a new example.

After you have a couple of passing examples, the refactoring
opportunities start to appear.

At each stage, try to think of the system right now as a complete
system based on the examples that are already passing. If the first
example you write is this:

describe Account do
context “when first created” do
it “has a zero balance” do
#…
end
end
end

… then, at this point, you have an application that lets you create an
account object with a zero balance. Does the code you have right now
serve its purpose well? Are the names all the right names, given that
this is the entire application? Is the code as well factored as it needs
to be to satisfy this single requirement?

There is a saying that as soon as you get the first example passing, the
rest of your job is maintenance. So now you add a second example using
the same process. Add just enough test to get red, then just enough
implementation to get green, then look for refactoring opportunities.
Rinse, repeat.

It take a fair amount of discipline to commit to this cycle, but once
you get the hang of it it moves really, really quickly.

‘end result’ mapped out before I write up the method.

implement it’s behavior? It takes so long to get the request specs
and method specs written and then I end up having to re-write many of
them because of how I implemented the method.

Does anyone have thoughts on how this is supposed to be done in a TDD
fashion?

It’s difficult to know if the 27 examples are the right 27 examples
without seeing them. Feel free to post the spec if you want some more
feedback, though even seeing them isn’t necessarily going to help anyone
to help you understand the process.

I’d recommend you give two resources a read: one, of course, is The
RSpec Book. The first part of the book is a step by step tutorial that
walks you through the process of driving out some code with a
combination of application-level and object-level examples. It’s not a
Rails app, but it’s the same process as going from request specs
(application level) to model specs (object level).

For a sense of where this all started, I’d recommend Kent Beck’s
Test-Driven Development by Example. Kent is known for inventing TDD, and
the examples in his book are very simple and clear.

HTH,
David

This forum is not affiliated to the Ruby language, Ruby on Rails framework, nor any Ruby applications discussed here.

| Privacy Policy | Terms of Service | Remote Ruby Jobs