Rspec在测试分页时给出假阴性

时间:2012-06-05 20:59:58

标签: ruby-on-rails rspec will-paginate

我正在撰写请求规范,以测试 will_paginate 是否正常工作,我遇到了一些问题。首先,这是我的规范的修剪版本:

require 'spec_helper'

describe "Articles" do

  subject { page }

  describe "index page" do

    let(:user) { FactoryGirl.create(:user) }

    before { visit news_path }

    describe "pagination" do

      before(:all) { 31.times { FactoryGirl.create(:article, user: user) } }
      after(:all) { Article.delete_all; User.delete_all }

      let(:first_page)  { Article.paginate(page: 1) }
      let(:second_page) { Article.paginate(page: 2) }

      it "should not list the second page of articles" do
        second_page.each do |article|
          page.should_not have_selector('li', text: article.title)
        end
      end
    end
  end
end

正如您所看到的,有一项测试可确保用户访问文章索引页时不会显示第二页文章。此测试失败:

1) Articles index page pagination should not list the second page of articles
   Failure/Error: page.should_not have_selector('li', text: article.title)
   expected css "li" with text "Article number 1" not to return anything

我无法理解为什么会失败。当我在开发环境中手动创建31篇文章并在浏览器中查看它时,分页工作正常,但是当我切换到测试环境时,规范会失败。

文章模型:

class Article < ActiveRecord::Base
  attr_accessible :body, :title
  belongs_to :user

  validates :user_id, presence: true

  default_scope order: 'created_at DESC'
end

文章工厂看起来像这样:

FactoryGirl.define do
  factory :article do
    sequence(:title)  { |n| "Article number #{n}" }
    body "This is the body"
    user
  end
end

1 个答案:

答案 0 :(得分:4)

非常令人难以置信的是,解决方法是执行以下操作;

更改:

before(:all) { 31.times { FactoryGirl.create(:article, user: user) } }

为:

before do
  31.times { FactoryGirl.create(:article, user: user) }
  visit news_path
end

我在这里学到的两件事:

  1. before块不得定位(:all),否则测试失败
  2. 我需要在前一个块中明确运行visit news_path创建工厂之后,否则capybara的页面对象将不是我期望的那样
  3. 所以,举例说明:

    这不起作用:

    # fails because it targets (:all)
    before(:all) do
      31.times { FactoryGirl.create(:article, user: user) }
      visit news_path
    end
    

    这也不会:

    # fails because we are visiting the news path before the objects exist
    before do
      visit news_path
      31.times { FactoryGirl.create(:article, user: user) }
    end
    

    需要这样:

    # not targeting (:all) and only visiting news path after creation of the objects
    before do
      31.times { FactoryGirl.create(:article, user: user) }
      visit news_path
    end
    

    超过20个小时来解决这个问题,至少我学到了一些新东西等。