0

我一直在使用 Devise 学习 Rails 3,到目前为止,它似乎运行良好。我有自定义会话和注册控制器,recaptcha 正在工作,登录用户可以通过 carrierwave 上传头像,该头像保存在 S3 上。对我的进步很满意。

现在我正在编写 Rspec 测试。没那么顺利!我有一个合理的用户模型测试,但那是因为我在网上找到了它(https://github.com/RailsApps/rails3-devise-rspec-cucumber/)并且能够通过跟随 Michael Hartl 的优秀“Ruby on Rails 3 教程”。

我真正的问题是控制器测试和集成测试,尤其是控制器测试。最初我以为我可以转换迈克尔书中的测试,我必须达到一个很小的程度,但进展缓慢,而且我似乎经常用头撞砖墙 - 我认为部分原因是因为我不我不太了解 Rspec 和 capybara(犯了一些非常愚蠢的错误),但也因为我对 Devise 的理解不够好,我想知道 Devise 是否能像 Rspec 一样出色地发挥作用;我在某处读到,因为 Devise 是基于 Rack 的,它可能并不总是像人们期望的那样使用 Rspec。不知道是真是假?

我知道有些人会想知道为什么这可能是必要的,因为 Devise 是一个 gem,因此已经过测试,但是我有几个例子,其他地方的更改在我没有立即意识到的情况下破坏了登录或注册。我认为一套好的控制器和集成测试可以解决这个问题。

如果我自己能够做到这一点,我会并且我会为其他人发布它,但到目前为止,编写这些测试非常痛苦,我真的需要继续做其他事情。

我敢肯定,我不会是唯一一个可以使用它的人。有人知道这样一套测试吗?

为了回应杰西的帮助...

这是我的registrations_controller_spec。“应该呈现'编辑'页面”中的评论显示了我正在努力解决的问题。此外,“应该创建一个用户”有一些我尝试过测试但无法做到的事情:

require File.dirname(__FILE__) + '/../spec_helper'

describe Users::RegistrationsController do
  include Devise::TestHelpers
  fixtures :all
  render_views

  before(:each) do
    @request.env["devise.mapping"] = Devise.mappings[:user]
  end

  describe "POST 'create'" do
    describe "failure" do
      before(:each) do
        @attr = { :email => "", :password => "",
                  :password_confirmation => "", :display_name => "" }
      end

      it "should not create a user" do
        lambda do
          post :create, :user_registration => @attr
        end.should_not change(User, :count)
      end

      it "should render the 'new' page" do
        post :create, :user_registration => @attr
        response.should render_template('new')
      end
    end

    describe "success" do
      before(:each) do
        @attr = { :email => "user@example.com",
                  :password => "foobar01", :password_confirmation => "foobar01", :display_name => "New User" }
      end

      it "should create a user" do
        lambda do
          post :create, :user => @attr
          response.should redirect_to(root_path)
          #response.body.should have_selector('h1', :text => "Sample App")
          #response.should have_css('h1', :text => "Sample App")
          #flash[:success].should == "A message with a confirmation link has been sent to your email address. Please open the link to activate your account."
          #response.should have_content "A message with a confirmation link has been sent to your email address. Please open the link to activate your account."
        end.should change(User, :count).by(1)
      end

    end

  end

  describe "PUT 'update'" do
    before(:each) do
      @user = FactoryGirl.create(:user)
      @user.confirm! # or set a confirmed_at inside the factory. Only necessary if you are using the confirmable module
      sign_in @user
    end

    describe "Failure" do

      before(:each) do
        # The following information is valid except for display_name which is too long (max 20 characters)
        @attr = { :email => @user.email, :display_name => "Test", :current_password => @user.password }
      end

      it "should render the 'edit' page" do
        put :update, :id => subject.current_user, :user => @attr

        # HAVE PUT THE DEBUGS THAT I'D LIKE TO GET WORKING FIRST
        # Would like to be able to debug and check I'm getting the error(s) I'm expecting
        puts subject.current_user.errors.messages # doesn't show me the errors
        # Would like to be able to debug what html is being returned:
        puts page.html # only return the first line of html

        # Would like to be able to determine that this test is failing for the right reasons
        response.should have_content "Display name is too long (maximum is 20 characters)" # doesn't work

        response.should render_template('edit')
      end
    end

    describe "Success" do

      it "should change the user's display name" do
        @attr = { :email => @user.email, :display_name => "Test", :current_password => @user.password }
        put :update, :id => subject.current_user, :user => @attr
        subject.current_user.reload
        response.should redirect_to(root_path)
        subject.current_user.display_name == @attr[:display_name]
      end

    end
  end

  describe "authentication of edit/update pages" do

    describe "for non-signed-in users" do

      before(:each) do
        @user = FactoryGirl.create(:user)
      end

      describe "for non-signed-in users" do

        it "should deny access to 'edit'" do
          get :edit, :id => @user
          response.should redirect_to(new_user_session_path)
        end

        it "should deny access to 'update'" do
          put :update, :id => @user, :user => {}
          response.should redirect_to(new_user_session_path)
        end

      end

    end
  end

end
4

2 回答 2

1

根据Devise Wiki,控制器测试必须是某种混合(单元 + 集成)测试。您必须在数据库中创建用户(或您的身份验证实体)的实例。模拟设计的东西真的很难,相信我。

试试这个:How-To:-Controllers-and-Views-tests-with-Rails-3-and-rspec

使用 Cucumber,您可以创建一个已经完成登录过程的步骤。

希望能帮助到你。

于 2012-10-26T20:04:28.077 回答
0

好的,所以有几件事可以使这项工作:

以下是您应该如何测试正文是否具有特定文本(您缺少 .body

response.body.should include "Display name is too long (maximum is 30 characters)"

您还可以测试@user 是否有错误:

assigns[:user].errors[:display_name].should include "is too long (maximum is 30 characters)"

但是,您确实需要使名称的长度超过 20/30 个字符,因此我将发布的属性更改为:

@attr = { :email => @user.email, :display_name => ("t" * 35), :current_password => @user.password }

https://gist.github.com/64151078628663aa7577

于 2012-10-27T18:31:10.873 回答