Hitting a wall in RSpec User Stories Integration Testing

Posted by teem on March 22, 2008

Hit a wall today.

I had just finished a bunch of RSpec tests and the implementation. All green.

I went back to an RSpec user story to checkout if everything integrated well.

Nope.

A scenario wherein a user tries to access a non-existing resource failed.

The steps involved looked like this:

When "the user requests for the non-existing book" do
  get "/books/1/"
end

Then "the browser should get a 404" do
  status.should == 404
end

The result of the test? I get the status of 500 instead of the expected 404. (The response object seems to be unset when the exception was raised.)

This shouldn’t happen. RecordNotFound exceptions in Rails are handled by default with a 404 by the ActionController::Rescue module.

So I went on to test it using the IntegrationTest.

class BooksAccessTest < ActionController::IntegrationTest
  def test_book_non_existent
    get "/books/1/"
    assert_equal 404, status
  end
end

The test passes.

So, where does this leave me? I’m not sure how RSpec handles exceptions in the integration code, but the test based on the Rails built-in integration test passes.

One thing I realized about the difficulty of writing tests, especially if you’re new, is that when something goes wrong, it’s much harder to spot the source of the bug: it could be your test, or your implementation, or the tool you’re using.

I’ll try to replicate this to see if this behavior is consistent.

Update

I’ve replicated the problem I encountered as described in the previous post.

To keep it simple, I made an index method that does nothing but raise a RecordNotFound exception.

# The controller
class TasksController < ApplicationController
  def index
    raise ActiveRecord::RecordNotFound
  end
end

Okay. Now for the integration tests.

# IntegrationTest
class TaskControllerIntegrationTest < ActionController::IntegrationTest
  def test_index
    get "/tasks/"
    assert_equal 404, status
  end
end

The test passes.

$ rake test:integration
(in /Users/Tim/sandbox/intest)
/opt/local/bin/ruby -Ilib:test "/opt/local/lib/ruby/gems/1.8/gems/rake-0.8.1/lib/rake/rake_test_loader.rb" "test/integration/task_controller_integration_test.rb"
Loaded suite /opt/local/lib/ruby/gems/1.8/gems/rake-0.8.1/lib/rake/rake_test_loader
Started
.
Finished in 0.168068 seconds.

1 tests, 1 assertions, 0 failures, 0 errors

Now, for the RSpec test.

# The plain text story
Story: User views a task

As a user
I want to view the details of a task
So that I can perform it well

  Scenario: I view a non-existent task by typing a random task number as a url
    Given there are no tasks
    When I try to view a task
    Then I should get a 404

# RSpec steps
steps_for(:tasks) do
  Given "there are no tasks" do
  end

  When "I try to view a task" do
    get "/tasks/1"
  end

  Then "I should get a 404" do
    status.should == 404
  end
end

The test fails.

    ...
    When I try to view a task
    Then I should get a 404 (FAILED)

1 scenarios: 0 succeeded, 1 failed, 0 pending

FAILURES:
    1) User views a task (I view a non-existent task by typing a random task number as a url) FAILED
    Spec::Expectations::ExpectationNotMetError: expected: 404,
     got: 500 (using ==)
    stories/tasks_story.rb:12:in `I should get a 404'
stories/tasks_story.rb:16