黄瓜故事的会话变量

Mat*_*age 16 testing rspec ruby-on-rails webrat cucumber

我正在为一个"注册"应用程序编写一些Cucumber故事,该应用程序有许多步骤.

而不是写一个Huuuuuuuge故事来同时覆盖所有步骤,这将是坏事,我宁愿像常规用户一样在控制器中完成每个动作.我的问题在于我将在第一步中创建的帐户ID存储为会话变量,因此当访问步骤2,步骤3等时,将加载现有的注册数据.

我知道能够controller.session[..]在RSpec规范中访问但是当我尝试在Cucumber故事中执行此操作时它失败并出现以下错误(并且,我也读过某处这是一个反模式等...):

使用controller.session [:whatever]或session [:whatever]

You have a nil object when you didn't expect it!
The error occurred while evaluating nil.session (NoMethodError)
Run Code Online (Sandbox Code Playgroud)

使用会话(:无论如何)

wrong number of arguments (1 for 0) (ArgumentError)
Run Code Online (Sandbox Code Playgroud)

因此,似乎加入会话存储是不可能的.我想知道的是,是否可能(我想哪个会是最好的......):

  1. 模拟会话商店等
  2. 在控制器和存根中有一个方法(例如get_registration,它分配一个实例变量......)

我查看了RSpec书(好吧,浏览过)并浏览了WebRat等,但我还没有真正找到问题的答案......

为了澄清一点,注册过程更像是一个状态机 - 例如用户在注册完成之前通过四个步骤前进 - 因此"登录"实际上不是一个选项(它打破了网站工作原理的模型) )...

在我对控制器的规范中,我能够根据会话var加载对方法的调用 - 但是我不确定'antipattern'行是否也适用于存根和模拟?

谢谢!

rya*_*anb 25

我会重复danpickett说黄瓜应该尽可能避免嘲笑.但是,如果您的应用程序没有登录页面,或者性能可能有问题,则可能需要直接模拟登录.

这是一个丑陋的黑客,但它应该完成工作.

Given /^I am logged in as "(.*)"$/ do |email|
  @current_user = Factory(:user, :email => email)
  cookies[:stub_user_id] = @current_user.id
end

# in application controller
class ApplicationController < ActionController::Base
  if Rails.env.test?
    prepend_before_filter :stub_current_user
    def stub_current_user
      session[:user_id] = cookies[:stub_user_id] if cookies[:stub_user_id]
    end
  end
end
Run Code Online (Sandbox Code Playgroud)


dan*_*ett 19

在黄瓜情景中,嘲笑很糟糕 - 它们几乎都是反模式.

我的建议是编写一个实际记录用户的步骤.我这样做

Given I am logged in as "auser@example.com"

Given /^I am logged in as "(.*)"$/ do |email|
  @user = Factory(:user, :email => email)
  @user.activate!
  visit("/session/new")
  fill_in("email", :with => @user.email)
  fill_in("password", :with => @user.password)
  click_button("Sign In")
end
Run Code Online (Sandbox Code Playgroud)

我意识到实例变量@user是一种糟糕的形式 - 但我认为在登录/退出的情况下,拥有@user肯定是有帮助的.

有时我称之为@current_user.


小智 17

回覆.Ryan的解决方案 - 您可以在env.rb文件中打开ActionController并将其放在那里以避免放入您的生产代码库(感谢john @ pivotal labs)

# in features/support/env.rb
class ApplicationController < ActionController::Base
  prepend_before_filter :stub_current_user
  def stub_current_user
    session[:user_id] = cookies[:stub_user_id] if cookies[:stub_user_id]
  end
end
Run Code Online (Sandbox Code Playgroud)


Pir*_*sko 5

我不知道这与原来的问题有多大关系,但我决定以讨论的精神发帖...

我们有一个黄瓜测试套件,运行时间超过10分钟,所以我们想做一些优化.在我们的应用程序中,登录过程会触发大量与大多数场景无关的额外功能,因此我们希望通过直接设置会话用户ID来跳过此功能.

Ryanb的上述方法效果很好,除了我们无法使用该方法注销.这使我们的多用户故事失败了.

我们最终创建了一个仅在测试环境中启用的"快速登录"路由:

# in routes.rb
map.connect '/quick_login/:login', :controller => 'logins', :action => 'quick_login'
Run Code Online (Sandbox Code Playgroud)

以下是创建会话变量的相应操作:

# in logins_controller.rb
class LoginsController < ApplicationController
  # This is a utility method for selenium/webrat tests to speed up & simplify the process of logging in.
  # Please never make this method usable in production/staging environments.
  def quick_login
    raise "quick login only works in cucumber environment! it's meant for acceptance tests only" unless Rails.env.test?
    u = User.find_by_login(params[:login])
    if u
      session[:user_id] = u.id
      render :text => "assumed identity of #{u.login}"
    else
      raise "failed to assume identity"
    end
  end
end
Run Code Online (Sandbox Code Playgroud)

对我们来说,最终比使用cookies数组更简单.作为奖励,这种方法也适用于Selenium/Watir.

缺点是我们在应用程序中包含与测试相关的代码.就个人而言,我认为添加代码以使应用程序更易于测试是一个巨大的罪恶,即使它确实增加了一些混乱.也许最大的问题是未来的测试作者需要弄清楚他们应该使用哪种登录方式.凭借无限的硬件性能,我们显然不会做任何这样的事情.