我创建了一个 RSpec 规范来测试 POST #create 操作是否正常工作:
describe "POST #create" do
it "creates a career" do
expect {
post "/careers/", career: attributes_for(:career)
}.to change(Career, :count).by 1
end
end
上面的代码工作正常。当我创建另一个测试以仅允许具有"admin"角色的用户时,就会发生此问题。我是否需要创建一个新用户,登录他们,然后运行上述测试?对于所有基于用户角色的限制的未来测试,我是否需要执行此操作?
有没有另一种方法可以进行这种类型的测试?1(只需测试创建方法是否有效,并且 2( 仅允许具有"管理员"角色的用户访问 GET #new 和 POST #create 方法?
当您的功能完全开发后,您需要进行以下测试:
- 一个快乐路径测试,其中管理员创建职业
- 非管理员试图创建职业但被阻止 这样做可能是另一个未登录用户
- 尝试创建职业但被阻止这样做(您是否需要这取决于您是否必须编写不同的代码来处理未登录和登录的非管理员用户(,以及
- 可能是管理员创建职业的不同场景的其他测试。
这种拥有一个完整的快乐路径测试的想法是测试中最基本的模式之一,但我不知道它有一个名字,除了"快乐路径"一词所暗示的。
看起来你正在做TDD。伟大!为了从您现在的位置到上面的测试列表,要编写的下一个测试是阻止非登录用户创建职业的测试。要使两个测试同时通过,您需要更改第一个测试以登录管理员。如果您需要更多成功创建职业的测试(项目符号 4(,是的,您也需要在这些测试中登录管理员。
旁注:
-
除非你已经有了它,否则我会把你的快乐路径规范写成一个功能规范(验收测试(,而不是一个控制器规范,以便你指定UI的重要部分,并对整个堆栈进行集成测试。失败的身份验证规范可能用作控制器规范,但你可能决定在用户没有至少其中一个方案的权限时需要接受测试 UI。
-
我真的不喜欢这种语法
expect {}.to change
。它可以防止您对发布结果做出任何其他期望。在您的示例中,我希望 HTTP 响应状态为 200 (response.should be_success
(。不过,正如我所说,我的第一个规范将是功能规范,而不是控制器规范。
所以,这是一个有趣的问题。是的,您绝对应该(IMO(独立于目标方法/操作测试身份验证。其中每个都构成一个功能单元,应按此进行测试。
在我目前的项目中,我更喜欢PORO(我经常将它们保存在一个名为"管理器"的目录中,尽管我知道很多人更喜欢称它们为"服务"(用于各种事情,因为它可以让我隔离功能并独立测试它。所以,我最终可能会得到这样的东西:
# controllers/foo_controller.rb
class FooController < ApplicationController
before_action :authenticate
def create
@results = FooManager.create(params)
redirect_to (@results[:success] ? my_happy_path : my_sad_path)
end
def authenticate
redirect_to unauthorized_path unless AuthenticationManager.authenticate(params, request)
end
end
# managers/foo_manager.rb
class FooManager
class << self
def create(params)
# do a bunch of great stuff and return a hash (perhaps a
# HashWithIndifferentAccess, if you like) which will
# allow for evaluation of @results[:success] back in the
# controller.
end
end
end
# managers/authentication_manager.rb
class AuthenticationManager
class << self
def authenticate(params, request)
# do a bunch of great stuff and return a boolean
end
end
end
通过这样的方法,我可以轻松地独立测试FooManager.create
和AuthenticationManager.authenticate
(以及FooController.create
和FooController.authenticate
路由(。万岁!
现在,正如 Dave 非常指出的那样,您的身份验证框架或控制器方法在单元级别是否正常运行,与整个系统是否按预期运行是一个单独的问题。我和他一起进行高级集成测试,这样你就可以清楚"完成"是什么样子的,你知道什么时候该大喊"发货!