views:

382

answers:

1

I have a Sinatra app that serves pages as read-only or editable depending on if the user is logged in.

The controller sets a variable @can_edit, that is used by the views to hide/show edit links. How can I test @can_edit's value in my tests? I have no idea how to get at the current instance of the controller under Rack::Test.

I use class_eval to stub the logged_in? method in the controller, but I'm having to resort to checking last_response.body for my edit links to see if @can_edit has been set or not.

How can I test the value of @can_edit directly?

+4  A: 

Unfortunately I don't think this is possible without modifying Rack::Test. When you make a request during application testing, Rack::Test does the following:

  1. adds the request to a list of recent requests
  2. creates a new instance of your application and invokes its call method
  3. adds your application's response to a list of recent responses

It's easy to access the last_request and last_response, but unfortunately no information is saved about the state of your application while it's running.

If you're interested in hacking together a Rack::Test patch to do this, start by looking at rack-test/lib/rack/mock_session.rb on line 30. This is where Rack::Test runs your application and receives the standard Rack app return values (status, headers, body). My guess is that you're going to have to modify your application as well, to collect and make accessible all of its instance variables.

In any case, it's best to test for results, not implementation details. If you want to make sure an edit link is not visible, test for the presence of the edit link by DOM id:

assert last_response.body.match(/<a href="..." id="...">/)
Alex Reisner
"it's best to test for results, not implementation details" I've seen similar statements like this before, and I have to disagree. If you want 2, 1 + 1 works quite well, but so does 1 + 2 + 10 - 11. Neither of which means your application is "actually working properly".
nowk
I don't completely disagree with you, however: let's say there is a method that is implemented incorrectly. If the method returns the right answer 100% of the time (you can't think of a case where it fails) then is the implementation really "incorrect?" Does it matter?If you find yourself testing the values of variables within methods, you may not have enough test cases (inputs). If you rename variables or otherwise change your application's implementation without changing its behavior, your tests should pass without modification. This is a big reason for using tests in the first place.
Alex Reisner
I think that testing @can_edit is testing the output of the controller. I don't like testing it indirectly by checking the view for what should happen when @can_edit is set. That should be a different test, solely for the view.
Brian