Rails 5 Controller Tests
controller tests 不再是 unit tests
Rails 5 的 controller tests 现在成了 integration tests。这意味着好多内部交互的功能都被移除了。如果你过去的项目因为某些原因撸了一大堆 controller tests,那你会发现有一大堆过去在测试代码里面用的 hacks 技巧都不能再用了。
ActionController::TestCase is deprecated
Rails 5 的 controller tests 继承自 ActionDispatch::IntegrationTest。
class ProductsControllerTest < ActionController::TestCase
def test_index_response
#...
end
end
# Rails 5
class ProductsControllerTest < ActionDispatch::IntegrationTest
def test_index
#...
end
end
URLS, not actions, are required.
Rails 5 要求我们在测试中使用 URL Helper 来指定路由。
# Rails 4
get :index
get :index, { id: 1 }
# Rails 5
get root_path
get posts_path(@post)
Use of Keywords arguments in HTTP request methods
我们需要明确的给出 params 参数关键字。
Rails 4.x, 我们可以一次传递各种参数,比如: params, flash messages 和 session variables。但是 Rails 5 要求我们必须明确给定参数名称。
# Rails 4
get :show, { id: user.id }, { notice: 'Welcome' }, { admin: user.admin? }
# Rails 5
post posts_path, params: { post: { title: "First post", body: "This is the body"} }
No more access to request
request 对象被移除。
# Rails 4
request.env["HTTP_AUTHORIZATION"] = something....
# Rails 5
get admin_path, headers: {'HTTP_AUTHORIZATION' => something }
No more access to session
你不能再利用给 session 赋值的方式实现授权之类的操作了。现在你必须真实的触发登录页面,DHH 对此的解释。
def sign_in_as(name)
post login_url, params: { sig: users(name).perishable_signature )
end
setup { sign_in_as 'david' }
这看起来就像我们过去在 integration tests 中干的事一样。没错,因为现在 controller tests 就是 integration tests 了。没啥可惊喜的,但是为了兼容,你不得不修改你的一大堆测试代码。
No more access to assigns and assert_template
不能再使用 assigns 来访问控制器中的实例变量,也不能使用 assert_template 来验证该 action 渲染的是指定的某个 template。它们都被移除了。你可以换用 assert_select 来判断页面中或响应中的节点内容,以验证结果。
原因是这样的,老大们觉得实例变量和渲染哪个模板那是控制器内部实现的细节,新版的 controller tests 不应该关注这些东西。按照 Rails 核心团队的说法,controller tests 应该关注的是 action 的结果(返回的 cookies 和 HTTP 状态码正确)。
结论
Rails 中再也没有功能测试 controller tests 这一说法了,现在它成了集成测试 integration tests。那以前的 integration tests 怎么办呢?将来再说。
