TDD killing my joy of Rails

some people take the approach of stubbing all the tests you can think of before you write the code (def test_should_incinerate_pie; end), making sure the code more or less works, then running the existing test suite to verify that you haven't broken anyway, and last, actually writing the contents of all those tests you stubbed out. it isn't as pure as tdd, but it does accomplish some of the major goals (think about what should work and how, and be able to validate that you have no regressions).

-faisal

Despite all of the stuff you hear about how it will save you time in the future, you’ll know when it breaks, etc, there is one huge benefit that you will soon realize that, to me, outweighs the rest:

It forces you to think about your logic twice. Once when you write your tests, and once again when you write your code.

Unit tests let you get your business rules into code really quickly. If you do all of your business logic in the models, then this is more apparent. For example… you may create a new user, but doing so will mean that he will need to be assigned a default role and some basic rights. You might consider doing that in the user model’s after_save callback.

The smart thing to do (because you can’t easily see this from the web interface) would be to write the test first.

def test_user_default_roles_created u = User.create :username =>“homer”, :password=>1234

# user should have only one role... guest
assert_equal 1, u.roles.size
# more code would go here to actually verify that the "guest" role is assigned to the user by the callback

end

Doing that first helps me think about the end result and also helps me decide if that is in fact the way I want to do it… maybe I don’t want to assign the role automatically… maybe I want something else to happen instead.

Just my thoughts… I’m doing my best to convert more people to TDD and am working on a tutorial that helps explain how I use it to build apps… The Peepcode one rocks too so check that out as well.

Brian Hogan wrote:

It forces you to think about your logic twice.

I hate that part. I just want to claw my way from the submit_tag to the database and then collapse.

However, I don't want to have to do that again and again and again. I want my own workflow to be DRY.

Faisal N Jawdat wrote:

some people take the approach of stubbing all the tests you can think of before you write the code (def test_should_incinerate_pie; end), making sure the code more or less works, then running the existing test suite to verify that you haven't broken anyway, and last, actually writing the contents of all those tests you stubbed out. it isn't as pure as tdd, but it does accomplish some of the major goals (think about what should work and how, and be able to validate that you have no regressions).

The goal is to make very few edits between test runs, and always predict the result of each test run. Either predict that all the tests pass, or predict what kind of error diagnostic you will see.

Don't edit for a long time then expect tests to pass.

Configure your editor - whatever it is - to run all your tests when you hit F5.

Even better… install ZenTest

gem install ZenTest

autotest --rails

Tests run when you save the corresponding file. Makes it almost too easy.

Jeff Pritchard wrote:

The job before us involved creating both a new XML based GUI layer and also the glue and support code needed to hook that to an existing set of "middleware" (this is phone UI stuff). I was doing the glue/support code, and he was in charge of writing the XML stuff. He helped me realize that the easy way for him to communicate just what he needed from my part, was to write a test. He would send me an email something to the effect of "I just added a test for BLAH", and then I would go off and write some stuff that makes his test pass, then he would hook that up to his XML and goodness would happen.

Nice - tests to define internal interfaces.

Note that fix requests to the Rails and related code repositories these days typically come with failing test cases.

And because of the TDD approach, every little hunk of the project works perfectly (within the limits of the requirements we have defined -- i.e. the tests we have written) as we go, so there just isn't any of the old way of "OK, it's feature complete -- in a few months we should have some of it actually working right".

Shhhh! We need to keep that part a secret from the competition.

The few of them without pointy-haired bosses!

Brian Hogan wrote:

Even better... install ZenTest

gem install ZenTest

autotest --rails

Tests run when you save the corresponding file. Makes it almost too easy.

My command line:

trigger 'rake recent' `find test -name \\*.rb` app/*/*.rb app/views/*/*.rhtml

The utterly ugly and distastefully hacked-together contents of trigger are below my sig.

Any editor, folks. Any editor. I don't even need to look at the console to hear the results. If the punk rock ain't up too loud!

That’s pretty wild. I dig it.

Brian Hogan wrote:

That's pretty wild. I dig it.

With a little more work I'm going to get it to say "Ni!" when it passes and "Bad Zoot!" when it fails.

You don't need the -rails option, the latest version automatically recognizes the Rails project and runs all the tests.

How do I make my terminal show failures in red? I am on Mac. TIA.

} } You don't need the -rails option, the latest version automatically } recognizes the Rails project and runs all the tests. } } How do I make my terminal show failures in red? I am on Mac. TIA.

gem install turn

Then require 'turn' in test_helper.rb

--Greg

gem install turn

Then require ‘turn’ in test_helper.rb

–Greg

Will this work on iterm also?

does this require some particular TERM setting?

-faisal

} > } > gem install turn } > } > Then require 'turn' in test_helper.rb } > } > --Greg } } Will this work on iterm also?

I would expect so, but I don't use iterm. Try it out.

--Greg

} } On Dec 1, 2006, at 9:06 AM, Gregory Seidman wrote: } > gem install turn } > } > Then require 'turn' in test_helper.rb } } does this require some particular TERM setting?

I've only used it on an xterm, and it works just fine in that. I recommend trying it out and, if it doesn't work, sending a message to the author (not me!).

} -faisal --Greg

I am really interested in Behavior-Driven Development (BDD) with Rails. Rspec seems excellent for Ruby BDD and I have just started toying with the Rpsec on Rails plugin to run through some simple examples.

My question is, is it possible to implement Rspec on Rails for an existing Rails project and if so how?

Have a bunch of pre-existing projects that I would like to use Rspec on Rails on and I would hate to have to manually create all the nice directories and files that Rspec on Rails does when you use it from the beginning. Any help would be appreciated.

Thanks, Nathan

Nathan,

I'm in a similar position - a 6 month old app that I can't just drop all the current tests and go with rspec. I'm considering using test/spec to start switching to BDD on a spec by spec basis. It integrates with test/unit and doesn't require translating old tests to specs.

info here: leah blogs: Announcing test/spec 0.2, a BDD interface for Test::Unit

- rob

Anyone who wants their joy of TDD killed by Rails, dead, by an expert, please ping me privately. I have a shot at writing something up on this, and I need feedback and numbers first.

Working title, oh, I dunno, maybe...

  --> Test First Ajax <--

:wink:

Rob,

Cool, thanks for the link. Looks like just what I needed.

Nathan

Nathan,

  > My question is, is it possible to implement Rspec on Rails for an   > existing Rails project and if so how?

Give a try to the simply_bdd plugin.   http://svn.techno-weenie.net/projects/plugins/simply_bdd/README

It makes using RSpec a lot easier: you run rspec code like normal tests (see the example in the README page), and it works fine with autotest.

Not shown in the README example is the need to use    require 'spec' to access the should_** magic.

Example:

file: test/unit/a_user_test.rb require File.dirname(__FILE__) + '/../test_helper' require 'spec'

context "A User with no name" do     def setup       @user = User.new     end

    specify "should be invalid" do       # assert !@user.valid? # std way       @user.should_not_be_valid # rspec way     end end