Is “one assertion per test” a “false idol”?

BDD, Patterns, TDD — Tags: , , , — dc.rec1 @ 8:04 pm

A few days ago I wrote in my portuguese blog an article trying to demonstrate why the “one assertion per test” pattern is an excellent one. If you dont know much about this pattern, I suggest you to follow this link which is a post from Jay Fields talking about it.

Some people gave me some feedback in the comments and one of them pointed me to this post from the guys from thoughtbot where among other practices, they criticized the one I was trying to evangelize :)

I like arguments and in this case arguments are present, but I think they aren’t valid, we’ll see why.

6 database records created

The author of the posts shows a code written in Shoulda where before each test he creates a record in the database and claims that the pattern is bad because to follow it he needed to create six database records instead of just one. Now I ask, did anyone tell anybody to create a record before each test? In my first post talking about the pattern I wrote an example which contains the following code:

before :all do
  email = Email.new("morena@opensource.com")
end

Note that I wrote before :all and not before :each, that’s because independent of the pattern, the tests need to be smart. In the case you couldn’t specify in Shoulda a block to be executed before all tests, that’s a problem of the framework and not of the pattern.

TDD should feel rhythmic

In the same code talked before, the author wrote some tests consisting of one line (Shoulda macros) and others consisting of three lines. Then he argues that the pattern in discussion is bad because the code hasn’t rhythm and TDD should have rhythm. Does this have any sense? The pattern doesn’t talk about having tests in one line or three, just about having one assertion per test. This doesn’t have any relation with the pattern, I might have the same behavior without following it, like this:

should_respond_with_xml_for 'user' 
 
should 'include the user id and user name' do 
  assert_select 'id', @user.id.to_s 
  assert_select 'name', @user.name 
end

What about now? Can we say that Shoulda is bad because I wrote a code that I consider it has no rhyme? Are then Shoulda macros not that good because they take they rhythm of the code?

Test names are not intention-revealing

I’m not sure if I understood this argument very well but I think the author claimed that the more tests you have, the more you have to give specific names to them. Assuming I’m right in my understanding, the intent of the pattern is precisely this, to create tests that specify what they are testing and what the code should do. When you run your tests, I surely think it’s better to receive this:

a GET to /users/:id.xml should respond with success
a GET to /users/:id.xml should render template show
a GET to /users/:id.xml should find the correct User
a GET to /users/:id.xml should respond with xml for user
a GET to /users/:id.xml should include the user id
a GET to /users/:id.xml should include the user name

than

user show xml

I did write “user show xml” because the second code wrote by the author is a single test with the name “test_user_show_xml”. “user show xml” doesn’t tell us anything about the system. If I read this test I will think that the user must show a xml. The first case tells us much more about the system, it’s an executable specification.

If context/describe/should/it blocks want to make things shorter then why aren’t we using a library (Test::Unit) that makes them one line?

What relation does this have with the pattern? Again, the pattern just tells about having one assertion per test, not about leaving the code smaller. Moreover, I think this argument is good for the pattern. There are people who say that they don’t follow the pattern because they prefer to write less code. In this case, if you want to write less code then you should use Test::Unit :P

The author shows then the code written in Test::Unit that I talked about before, with a lot of asserts in only one test. I think this test is really bad because it doesn’t specify anything at all and to understand it you need to read the code, not just the title.

Finally, the post mentioned that the pattern is a solution for a problem that doesn’t exist, but the problem does really exists and it’s this:

Writing non-executable documentation of a code is very expensive because every change in the behavior of the code generates also a change in the documentation and that creates double work. Besides the double work, the non-executable documentation does not guarantee that the code does what it should. The solution to this is to create executable documentation and executable documentation means tests that specify and to create tests that specify the easiest solution is to follow “the one assert per test” pattern.

The GemHub way to create RubyGems.

RubyGems — Tags: , , , , — dc.rec1 @ 2:58 pm

What is GemHub?

GemHub is a gem that creates a simple directory structure to build a gem which is gonna be tested with RSpec and hosted on GitHub.

Why not use NewGem or Sow?

If you’re writing a gem and you’re planning to host it in GitHub then NewGem may be not the best option, because it was created with RubyForge in mind and creates a lot of stuff that with GitHub you don’t really need, like a history, post-installation and manifest files, a task folder for putting your tasks, a doc folder for documentation and some scripts generators.

When thinking in GitHub you don’t need a history file because you got Git’s commit history with a click. Also, you can write all kind of instructions in a Readme.textile and that information will appear in the repository site. If you need more detailed documentation, you can write them in the wiki. Finally, when writing a not so complex gem is much probably that you will not need any other task that GemHub’s defaults.

Sow, being a much more simpler option, also generates a history and manifest files. It does also create a Readme file, but with txt extension, what means not cool formatting for GitHub. A bin folder is created by Sow, too. The intention of the bin folder is to put scripts that will be executed in a terminal, what mosts gems don’t need.

Finally, both NewGem and Sow creates tests using Test::Unit. Writing tests with lots of asserts is very ugly when compared to RSpec’s cool expectations, so GemHub uses RSpec as they testing framework.

Working with GemHub

When executed:

gemhub gem_name

GemHub will create a spec/gem_name.rb file to specify your gem’s behavior, a lib/gem_name.rb to implement your gem specification, a README.textile file (with an MIT license included) to write whatever you want and a Rakefile with common tasks. In this Rakefile there are also the details from your gem (name, version, platform, etc).

      create  
      create  lib
      create  spec
      create  lib/gem_name.rb
      create  spec/gem_name_spec.rb
      create  README.textile
      create  Rakefile

Anytime before you get ready to create your gemspec file, you should open the Rakefile file and edit the gem details. With your Rakefile edited, you can run rake make_spec to generate the gemspec file of your gem, rake gem to build a gem from your gemspec file and rake install to install the built gem locally. It’s a good practice that before you push your code to GitHub you execute also rake specs to verify that your code operates as expected and rake gem to verify that your gemspec is OK, so GitHub can build your gem without problems.

This work is licensed under a Creative Commons Attribution-Noncommercial-Share Alike 3.0 Unported License.
(c) 2010 Diego Carrion | powered by WordPress with Barecity