When should I test Views separately in Cucumber & RSpec workflow? - ruby-on-rails

After some time of doing Cucumber & RSpec BDD, I realized that many of my Cucumber features are just higher level view tests.
When I start writing my scenario and then go down to RSpec, I don't ever write view specs, since I could just copy and paste part of the scenario, which would be ugly dupliacation.
Take this scenario for example
Scenario: New user comes to the site
Given I am not signed in
When I go to the home page
Then I should see "Sign up free"
I know that this isn't directly testing the view, but writing separate view spec to check for the same thing seems redundant to me.
Am I approaching Cucumber wrong? What exactly should I test in view specs?
Should I write them for every single view, for example testing views for actions like
def show
#project = current_user.projects.first
end
or should I just test more complex views?

It's a widely-accepted (and in my opinion, incorrect) Cucumber philosophy that views should never be tested within RSpec. The argument goes that since the behavior of the view can be described in Cucumber, RSpec should stick to what it knows best -- Models and Controllers.
I argue that the "human-readable" aspect of Cucumber makes some aspects of view-speccing important. For instance, I find view specs to work very well when working in parallel with a front-end developer. If a JavaScript developer knows that he'll want to hook into a selector on your page, it's important that your view provides that selector.
For example:
describe 'gremlins/show.html.haml' do
context 'given it is after midnight' do
it 'has a #gremlin_warning selector' do
Time.stub!(:now).and_return(Time.parse '2010-12-16 00:01:00')
rendered.should have_selector '#gremlin_warning'
end
end
context 'it is before midnight' do
it 'does not have a #gremlin_warning selector' do
Time.stub!(:now).and_return(Time.parse '2010-12-16 23:59:00')
rendered.should_not have_selector '#gremlin_warning'
end
end
end
Note that the specs do not describe the content, they are willfully brief, and they do not describe interaction behaviors. Because the view is the portion of your application that will change the most, view specs should be used sparingly.
tl;dr: View specs are for communicating a contract to other developers and should be used sparingly (but nonetheless should be used).

Personally, I never use view specs when using Cucumber. To me, acceptance tests make a lot more sense, and my complex views are generally Javascript-focused and cannot be tested using view specs.

Don't use view specs for anything, ever. Cucumber stories -- or even RSpec integration tests -- do that better. The examples bobocopy gives are good ones for the case he postulates, but they should be rolled into Cucumber stories/integration tests, not left on their own.

Related

rspec (with capybara) directory layout

After reading up on rspec 2 and capybara 2 I'm slightly confused regarding best practices as far as structural directory layout is concerned. There seems to be some overlap between the various specs (such as request specs and controller specs for instance), and I was wondering what is the "best practice" way of organising these files, and what should each spec test?
What I've gathered so far (which may be wrong) is the following:
spec/factories
Factories used by Factory Girl (if used)
spec/features
Capybara tests, which emulate the interaction between a user and your application.
spec/models
Tests for model validation
spec/controllers
Testing controller actions (#new, #edit, #create etc.)
spec/requests
Tests for integration between various controllers (one level 'higher' than controller specs)
spec/support
Files which define modules that could be useful to include in some of the specs.
spec/acceptance
Acceptance tests.
spec/views
Tests concerned with whether views were rendered correctly
I personally feel that for instance spec/views seems unnecessary in the sense that the capybara tests also are concerned with views (and how they look) and controller tests could easily also test whether or not a certain view is rendered.
What are your thoughts?
from my point of view spec/acceptance and spec/features are the same.
spec/views is something completely different, as you can test specific views or partials in isolation. this is very helpful for complex views and you don't need to have any browser simulator.
in regards to capybara spec, i use a different approach that you can read about here: https://gist.github.com/phoet/6683280#file-readme-md

What's a proper way of writing request specs in RSpec?

tl;dr: Jump to the last paragraph
Recently I've been trying to use RSpec's request specs to do some more targeted testing.
This is how my testing mostly looks:
general cucumber feature specification, i.e. user goes to a post with comment, upvotes on a comment and the author gets points
model specs for when the model actually has some functinality, i.e. User#upvote(comment)
controller specs where I stub most of the things and just try to make sure the code goes the way I expect
view specs for when there is something complex in the view, such as rendering a upvote link only when the user didn't already upvote, and these are stubbed as well
The problem is when I have some specific scenario which causes a bug and everything seems to work in the model/view layer where I am unable to reproduce it.
That forces me to write an integration test, which I can also do in cucumber. The problem arises once I am able to actually reproduce it, and I need to figure out why is it happening. This usually means playing around in tests, changing different things and seeing what happens.
For example create a comment that is owned by the user who is trying to upvote, try to vote with an expired session etc. However these are really huge pain to write in Cucumber, because of the need to write a scenario and then specify each step.
At this point, I prefer to write a request spec, because it is more low level and allows me to directly do stuff. The problem is, that I'm not really sure how to properly write a request spec, or what are the rules.
A simple example here is:
visit login_path
fill_in "Username", :with => user.username
fill_in "Password", :with => user.password
click_button "Log in"
vs
post sessions_path(:username => user.username, :password => user.password)
or even something more low level like
session[:user_id] = user.id # this actually doesn't work, but the idea is there
Both of these examples achieve the same thing, they'll log a user in. I know that the answer to which one to pick is based on what I need to test, but that doesn't answer the correct, conventional way to do this.
I've been trying to find something about request specs, but they're not really described anywhere. The RSpec book doesn't cover them, the RSpec documentation doesn't say anything either.
What is a correct way to write request specs? When should I use capybara and when just the Rails' #get and #post methods instead of clicking buttons and visiting paths?
For requests spec I believe the convention is to stick to testing user behaviour and interface interactions, which would mean loading the page, filling in the form etc. A website user cant set the session or interact with variables directly so neither should your request specs.
I've often been tempted to skip page loads and form interactions by posting or setting variables in request specs (for speeds sake, especially heavy ajax specs) but it really does break the purpose of a request spec.
As the comments mentioned, you should test the specific controller / view behaviour in the other spec types.
Sermon first....
I think the natural progression of YOU the test writer goes:
Controller
Model
Requests
a mix of Request, Controller and Model specs.
I know that I started looking at the controller first, cause it was easier to grasp.
You then get into Model specs, for non-happy path things...
Then you realize rspec doesn't actually render the view, so you are starting to see dumb errors in Airbrake, so you say, shoot... I need to test the views, and the workflow. Hence Request specs.
Lastly, you get older and realize, all 3 are important and should be used sparingly, but accordingly. I'm just at step 4 now... too many request specs, and you are slogging 5 mins for the whole suite on a medium sized app. sucks.
To answer your question:
I test workflow and views i need to be "seen" (with page.should or any tricky JS (jquery ui selectors for instance) with capybara in a request spec.
If i just need to make sure the controller variables are instantiated or to do something quick with a post for a non-happy path , out of workflow thing... I use the controller. E.g., POST to IPN Controller in paypal...
You'd be surprised how much this covers. This leaves you to test the models for all the whacked out stuff you need for total all the edge cases.
Honestly though, I'd say use Fixtures and Test Unit for integration tests... still like them better, faster... stronger... etc.

Can I make a rails cucumber defenition any shorter?

I'm getting started with cucumber, and I have written the following step definition, which basically I copied from the rspec test I already had.
Given /^There is a picture on the screen$/ do
describe PagesController do
describe "GET 'home'" do
it "should be successful" do
get 'home'
response.should be_success
end
end
end
end
Now I'm also quite new to Rails. But this seems a bit long to me, can't I make it any shorter?
What you're doing there is a big antipattern when writing tests with Cucumber. You haven't broken down your step far enough—when you look at the test you've got, you're actually going through at least a couple of different steps, one of which isn't something you want to test. A better test for this would be:
Given I am on the home page
Then I should see a picture
The first step you get for free when you install capybara's web steps, provided you are using the default path helper in features/support/paths.rb. The second one would look like this:
Then "I should see a picture" do
page.should have_selector("img.picture")
end
That step is going to look for an image with a 'picture' class on it—my arbitrary definition of what a picture is in the context of your application.
Notice that I'm not checking the response status here. The idea behind cucumber (even moreso than Rspec) is that you test things from the perspective of the client. Arguably your client may be a client API, so perhaps checking the status code is appropriate, but in general with a web app, you're much more concerned about the UI, and a failing status code will manifest itself in other ways, such as a broken UI. Details like status codes are generally implementation details that shouldn't be tested from a BDD point of view (though they should be covered in your unit tests.)
FWIW, I also disagree with the assertion that the length of the test is what should determine whether you should be using Rspec or Cucumber. See my blog post on the matter: http://collectiveidea.com/blog/archives/2011/04/15/language-matters/
It would strongly recommend not using Cucumber until you're more familiar with Rails/Ruby. Cucumber adds a level of abstraction that can make things very confusing, frustrating and time consuming. Just get very good with RSpec first. Then when you want to do integration tests on your Rails app, use Capybara with RSpec. When you're comfortable using those gems, you can go to Cucumber.
Cucumber is about writing user stories. You then translate those Cucumber steps into lines of RSpec and Capybara.
If you are looking for brevity, I would recommend sticking to RSpec. Cucumber's main advantage is its readability to people who do not write code, while RSpec sacrifices that in order to be shorter. I tried to use Lettuce, a python analogue to Cucumber, on one of my projects and found it to be way too much work to keep up.
So, in short: if you want to write shorter tests, use RSpec. If you want your developer to edit your tests or you are working in a team, use Cucumber.

Using RSpec, how to verify from tags and link tags in view pages?

In view pages, people use form tag helpers and link helpers etc.
If I then rename a controller, or a action, my view pages may break.
How can I unit test view related tags for this kind of a breakage?
So the term "unit test" is usually reserved for tests that only test one piece of an application at a time-- you test one view and you test it independently of the associated controller and model.
But as you have found, if you isolate the tests, you can break the interaction between the two and still have all your unit tests passing.
That's why it's important to have tests that exercise your whole application working together. These are sometimes called functional, integration, or acceptance tests (I don't find it very useful to distinguish between these terms but YMMV).
This is usually done using a browser simulator like capybara or webrat so that you are using the application exactly how a user would in the browser. They demand different techniques than unit tests do, so that you don't end up with very brittle tests or tests that take a long time to run without providing additional value for the time spent.
You can use various test frameworks to drive capybara, including RSpec. Many people use RSpec for unit tests and use Cucumber for integration tests. I highly recommend The RSpec Book, which also covers Cucumber and the different methods of testing and when you should use them.

How many use Rspec for controllers and views?

Are there strong reasons for using Rspec for controllers and views too?
My views are heavily dependent on Javascript, and as far as I know, Rspec doesn't handle javascript/ajax on views. Also im using Cucumber + Selenium for that.
And should I use it for controllers?
Isn't it enough to just use Cucumber + Selenium for the application behavior? Cause if a cucumber test passes, then it passes, why should I bother with Rspec view and controller tests?
Could someone enlighten me on this topic?
I use a combination of Cucumber + Shoulda, but what I'm about to tell you still applies to the setup you have.
When testing a controller I use Shoulda in a functional test to hit all of my "negative auth" situations. For example:
A logged in user trying to access an admin page.
A logged out user trying to access protected content.
User A trying to delete User B's post.
I use Shoulda for this, because what I'm generally looking for is that I was kicked to the login page, and that whatever model was trying to be accessed maliciously wasn't actually changed. I could use Cucumber for this, but I find it easier and less cumbersome to do with a handful of Shoulda macros and some functional tests. Shoulda contexts are a great fit here.
Then for the "good auth" situations, I use Cucumber. Things like:
A user accessing his own preferences page.
An admin pulling up reports.
These types of tests require that I check some actual page content, and not just check for "access denied" over and over again. I find the descriptiveness of Cucumber to be a great match here.
If you build a full enough set of tests, you can just use selenium, but if you want to test the behaviour of your javascript seperate from the rest of the app, you might consider using a javascript test framework, like QUnit.

Resources