Question

Using Rspec/Capybara for RSpec tests.

Assume that we have PostsController with basic CRUD. What to test? Creating new post(#new), showing all posts(#index), destroying post (#destroy), etc, like in the code below, or in another way: It allows user to create new post; when posts doesnt't exist it renders 404 ...; when user is blocked render 403 ?

require 'spec_helper'

feature 'Post management', js: true do
  background       { login_user }
  given!(:project) { create(:project) }

  scenario 'creating new post' do
    expect do
      visit new_project_post_path(project)
      fill_in 'post_title', with: 'Hello, I am the Doctor'
      fill_in 'post_text',  with: 'Trust me.'
      click_button 'Add post'
    end.to change(Post, :count).by(1)
  end

  given!(:project) { create(:project_with_posts) }

  scenario 'listing posts' do
    visit project_posts_path(project)
    project.posts.each do |post|
      page.should have_content post.title
    end
  end

  given!(:post) { create(:post) }

  scenario 'showing posts' do
    visit project_post_path(post.project, post)
    page.should have_content post.title
    page.should have_content post.text
  end
end
Était-ce utile?

La solution

This can only be an opinionated answer, but here are my rules of thumb regarding acceptance testing :

test the behavior expected by user

This is, as you mentionned "acceptance" testing : stackholder want to be provided with usual behavior for feature, not to be worried about what happen if something is invalid or user forgot to log in (controller specs already test that).

test what user should see

This is not the place to check if database is in correct state. Test flash messages and maybe what visually changed in a page (an item being or not being anymore in a list).

For example, in your "creating new post" scenario, you could test :

within '#flash_message' do
  page.should have_content 'Post created'
end

within '#posts' do
  page.should have_content "My new post"
end

You could write more specifics, but it would be duplication with unit tests, which are faster (why to check if Post.count is +1 if you can check Post received call to #create stub ?). Testing a few texts or elements on your page is enough to tell parts play well together.

Test an actual user behavior

No user "visits todo list item edition page". They begin from home page, then go to todo list, then click "edit" on the line of a specific item.

In your code, you could replace :

visit project_posts_path(project)

with :

def visit_posts
  visit '/'

  within '#projects' do
    first( 'a.posts' ).click
  end

end

scenario 'listing posts' do
  visit_posts
  project.posts.each do |post|
    page.should have_content post.title
  end
end

This is longer to run, but anyway, after one or two years of existence, your acceptance testing suite will be too long to run to just wait for it, you'll put it on a continuous integration server. And what matters here is to test everything works together as expected, not a specific behavior. There's no better way to do this than to start with home page (or any page an actual user would open directly, like admin home page, for example).

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top