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

9

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

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

但是这个测试并不正确。调用@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

当SessionsController#create动作执行时:

def create
  respond_to do |format|
      format.js {
        render nothing: true, status: 200
      }
  end
end

可以帮忙吗?https://dev59.com/D2Ag5IYBdhLWcg3wQ5Il - tmn4jq
很抱歉,我不认为这有帮助。我调用current_user时没有遇到问题。 - user1063998
.current_user” 是一种尝试登录用户的方法,还是一个实例变量的“attr_reader”?如果是前者,那么你所描述的似乎是预期的行为。 - max pleaner
current_user 是一个尝试登录用户的方法。如果您在完全空的控制器操作中运行我在问题中概述的测试,测试仍将通过。 - user1063998
你是如何在控制器中处理会话的?你是否使用Rails的session - Narasimha Reddy - Geeker
1个回答

2

在不改变问题中提出的代码的情况下,提供最小更改的解决方案:

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

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

这将使你的测试成为控制器有效测试。

解释:

我的假设是,你上面的测试总是成功的,因为用户已经登录(由在此之前运行的其他测试)。你可以通过在it后面的行中使用byebug并在bybug's控制台中运行current_user来验证这一点。如果它不是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

使用should change from nil to user语句,您可以验证测试开始前用户已注销,并在测试执行后用户已登录。
请注意,部分

   { sign_in_via_post user }.should change { current_user }.from(nil).to(user)

等同于以下代码(可能更易于理解)
   { sign_in_via_post user }.should change { user_signed_in? }.from(false).to(true)

正如这里讨论的那样。


谢谢您的回复。我相信current_user可以更新用户的状态。我已经在我的原始问题中添加了一个示例测试,我认为它说明了这个问题。 - user1063998
我突然想到,也许有一个 before_action/filter 在做某些事情,但我现在无法检查。也许你是对的。 - user1063998
@user1063998:你有机会测试我的建议吗?我花了相当多的时间来想出这个解决方案(至少我认为这是解决方案)。无论如何,这是一个很好的练习,但我更希望由提问者检查一下。 - Olli

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接