Rails Ruby on Rails 测试中怎么操作 Session?——深入理解 rails 测试中的 Session

derrick · 2017年04月12日 · 2163 次阅读

Rails 项目中,经常要编写集成测试来检验网站是否按正确的流程运行,这样的测试通常与 Session 有关。如果不能深入理解 rails 测试的运行方式,往往会产生许多困惑。下面是我对这方面的理解,希望可以解惑。

关键理解点:

1. 单元测试和集成测试的区别。

  • 单元测试(class ActiveSupport::TestCase)并没有运行全栈,sessions/ cookies hash 只保存在内存中,而不是 cookie jar 中。
  • 集成测试(class ActionDispatch::IntegrationTest)运行全栈—Rack middlewares, cookies, sessions。request 中的 sessions/ cookies 会经过 controller 保存到 cookie jar 中。

2. 单元测试和集成测试中操作 Session 时的不同。

  • 单元测试语句中可以直接操作 Session, 如:session[:user_id] = user.id, 因为 session hash 只是保存在内存中。
  • 集成测试中不能直接使用 Session,是因为 session 只有经过 controller 操作,才能保存到 cookie jar 中,而在集成测试中直接用session[:user_id] = user.id这样的语句,并不能保存到 cookie jar.
  • 并且集成测试是为了模拟软件真实的操作流程,而真实的操作发送/接收的是 HTTP request/ response,而不是session[:user_id] = user.id这样的语句。所以集成测试中不应出现直接修改 Session 的语句。

3. 集成测试中对 Session 是以什么方式处理的?

应该按照软件实际运行方式,发送 HTTP request 改变 Session。如发送post login_path, params: { session: { ....} } 登陆用用户。


案例分析:

SessionsHelper 中有以下方法:

def log_in(user)
  session[:user_id] = user_id
end

问:在 intergration test 中能不能使用 log_in 方法?

  1. helper 中的方法默认不能直接在 test 文件只使用。不过可以在test_helper.rb使用 include 语句调 helper 文件。
  2. 如果在 intergration test 中调用 log_in 方法,就相当于集成测试中直接对 session 进行修改,所以不能使用。

解决方法:

  • 在集成测试中直接写post login_path, params: { session: { ....} } ,发送 request, 通过 controller 修改 session,实现 log in .
  • 或者在 test_helper.rb 文件中,为class ActionDispatch::IntegrationTest类加一个方法,用来实现通过 request 登陆。比如:
class ActionDispatch::IntegrationTest
   def log_in_as(user, password: "password")
      post login_path, params: { session: { email: user.email, password: password } }
  end
end

然后就可以在 intergration test 中调用 log_in_as, 使程序更简洁。

derrick 关闭了讨论。 04月12日 17:04
derrick 重新开启了讨论。 04月12日 17:04
需要 登录 后方可回复, 如果你还没有账号请 注册新账号