Rails测试 - 检查用户是否使用Devise登录

use*_*998 8 ruby authentication ruby-on-rails devise warden

我试图通过向我发送POST请求来测试某人是否能够登录我的网站SessionsController.我在几个地方看到过这种推荐方式:

it 'must be able to sign in a user' do
  user = create(:user)
  post :create, format: :js, user: {email: user.email, password: user.password, remember_me: 0}
  assert_response :success
  @controller.current_user.must_equal user
end
Run Code Online (Sandbox Code Playgroud)

但这个测试不正确.调用@controller.current_user将尝试使用已发布的参数对用户进行身份验证,并user在提供的电子邮件/密码正确时返回.无法保证该create操作实际上是在调用sign_incurrent_user.

即使我重新编写测试以检查这些方法是否被调用,也可能会调用其他方法,例如sign_out.

是否有更明确的方法来最终检查用户是否已登录,如果是,用户是谁?

编辑 -

例如,以下测试将通过

it 'must sign in a user' do
   @controller.current_user.must_equal nil
   post :create, format: :js, user: {email: @user.email, password: @user.password, remember_me: 0}
   assert_response :success
   @controller.current_user.must_equal @user
end
Run Code Online (Sandbox Code Playgroud)

当SessionsController #create动作是:

def create
  respond_to do |format|
      format.js {
        render nothing: true, status: 200
      }
  end
end
Run Code Online (Sandbox Code Playgroud)

Oll*_*lli 2

对问题中建议的代码进行最小更改的解决方案:

测试开始前需要对系统进行初始化。尝试在 it 'must be able to sign in a user' do代码之前添加以下代码:

before (:each) do
  user = FactoryGirl.create(:user)
  sign_out user
end
Run Code Online (Sandbox Code Playgroud)

这应该将您的测试变成对后置控制器的有效测试。

解释:

我的假设是,上面的测试总是成功,因为用户已经登录(通过在此之前运行的其他测试)。您可以通过byebug在后面的行中使用itcurrent_userbybug's控制台中运行来验证这一点。如果不是nil,则用户已经登录,这将使您的测试无效。

请注意,(与上面评论中讨论的不同)current_user不会改变用户的状态;它是一个只读函数。

更短/更清洁的解决方案:

在我看来,有一种更干净的方法来执行这样的测试,如下所示:

def sign_in_via_post(user)
  post :create, format: :js, user: {email: user.email, password: user.password, remember_me: 0}
end

...

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

it 'must be able to sign in a user' do
   { sign_in_via_post user }.should change { current_user }.from(nil).to(user)
end
Run Code Online (Sandbox Code Playgroud)

使用该should change from nil to user语句,您可以验证用户在测试开始之前是否已注销以及在执行测试之后用户是否已登录。

请注意,该部分

   { sign_in_via_post user }.should change { current_user }.from(nil).to(user)
Run Code Online (Sandbox Code Playgroud)

相当于(也许更容易理解)代码

   { sign_in_via_post user }.should change { user_signed_in? }.from(false).to(true)
Run Code Online (Sandbox Code Playgroud)

正如这里所讨论的。