我已经在Rails上玩了几年了,并且已经开发出了几款在生产中还可以使用的应用程序.我一直避免做任何测试,但我已经决定纠正这一点.我正在try 为一个应用程序编写一些测试,这个应用程序是我为已经启动并运行但正在不断修改的工作编写的.我担心任何改变都会 destruct 一切,所以我想启动并运行一些测试.我读过RSpec的书,看了几段视频,但我很难开始(我觉得这是一种只有真正做到了才能理解的事情).

我正在try 写一个简单的测试我的ReportsController.我的应用程序的问题是,几乎所有的东西都在一个认证层后面.如果你没有登录,什么都不起作用,所以我必须先模拟登录,然后才能发送一个简单的get请求(尽管我想我应该编写一些测试,以确保没有登录的情况下什么都不起作用——我稍后再讨论).

我已经用RSpec、Capybara、FactoryGirl和Guard建立了一个测试环境(不确定要使用哪些工具,所以使用了Railscasts的建议).到目前为止,我编写测试的方式是在FactoryGirl中创建这样一个用户;

FactoryGirl.define do
  sequence(:email) {|n| "user#{n}@example.com"}
  sequence(:login) {|n| "user#{n}"}
  factory :user do
    email {FactoryGirl.generate :email}
    login {FactoryGirl.generate :login}
    password "abc"
    admin false
    first_name "Bob"
    last_name "Bobson"
  end
end

然后像这样写我的测试;

require 'spec_helper'

describe ReportsController do
  describe "GET 'index'" do
    it "should be successful" do
      user = Factory(:user)
      visit login_path
      fill_in "login", :with => user.login
      fill_in "password", :with => user.password
      click_button "Log in"
      get 'index'
      response.should be_success
    end
  end
end

这样失败了;

  1) ReportsController GET 'index' should be successful
     Failure/Error: response.should be_success
       expected success? to return true, got false
     # ./spec/controllers/reports_controller_spec.rb:13:in `block (3 levels) in <top (required)>'

有趣的是,如果我把我的测试改为response.should be_redirect,测试通过了,这对我来说意味着在那之前一切都在进行,但登录没有被识别.

所以我的问题是,我必须做什么才能让这个登录工作.我是否需要在数据库中创建与FactoryGirl凭据匹配的用户?如果是的话,FactoryGirl在这里有什么意义(我甚至应该使用它)?我如何在测试环境中创建这个假用户?我的认证系统是一个非常简单的brew 系统(基于Railscasts episode 250).这种登录行为可能必须在我的几乎所有测试中复制,那么我该如何在代码中执行一次并让它应用到所有地方呢?

我意识到这是一个大问题,所以我感谢你的关注.

推荐答案

答案取决于您的身份验证实现.通常,当用户登录时,您会设置一个会话变量来记住该用户,比如session[:user_id].控制器将在before_filter中判断登录,如果不存在此类会话变量,则重定向.我猜你已经在做类似的事情了.

要在测试中实现这一点,必须手动将用户信息插入会话.以下是我们在工作中使用的部分内容:

# spec/support/spec_test_helper.rb
module SpecTestHelper   
  def login_admin
    login(:admin)
  end

  def login(user)
    user = User.where(:login => user.to_s).first if user.is_a?(Symbol)
    request.session[:user] = user.id
  end

  def current_user
    User.find(request.session[:user])
  end
end

# spec/spec_helper.rb
RSpec.configure do |config|
  config.include SpecTestHelper, :type => :controller
end

现在,在我们的任何控制器示例中,我们都可以调用login(some_user)来模拟作为该用户登录.


我还应该提到,在这个控制器测试中,您似乎正在进行集成测试.通常,控制器测试只应模拟对单个控制器操作的请求,例如:

it 'should be successful' do
  get :index
  response.should be_success
end

这专门测试单个控制器操作,这是一组控制器测试中需要的.然后可以使用Capybara/Cucumber对表单、视图和控制器进行端到端集成测试.

Ruby-on-rails相关问答推荐

rails:如何在表单验证后使用涡轮刷新列表

form_with正在try 用错误的路径生成操作

删除链接不起作用,重定向 echo 示 Ruby

Grape api (rails) - 未初始化常量 Endpoints::TodoAPI (NameError)

如何在 Ruby on Rails 中正确存储 BigDecimal

使用rails form_for时带有_path的未定义方法

使用 rails 3.1.0 和 ubuntu 安装 Nokogiri 1.5.0 时出错

如何在 Rails 中使用 instance_eval 子句删除验证?

在 Epoch 中将 Ruby 时间戳转换为秒数并返回

如何在 rspec 测试中输出变量?

.increment vs += 1

如何获取包含表的列名的数组

在本地 Rails 开发环境中获取真实 IP 地址

登录delay_job?

如何使用 Rspec 判断 ActiveJob 中排队的内容

Postgresql JSON 数据列不同

Ruby 1.87 与 1.92 Date.parse

Rails - 邮件,将正文作为纯文本获取

Ruby on Rails Bootstrap Glyphicons 不工作

Ruby 中的类别名