即使是看似简单的索引操作也会让人感到非常复杂,无法单独测试。
我发现自己不得不嘲笑我的User
和Tenant
几种方法,只是为了通过before_filter
。然后我需要模拟Kaminari
和Tenant#users
来执行操作。
对于没有控制流的测试控制器动作,这感觉太过分了。
TDD原则会说过度需要嘲笑是设计不佳的标志,但后来我不确定如何将这个功能提取到域对象中。这是测试Rails控制器的这种痛苦的模拟标准吗?有没有更好的方法来做到这一点,我根本不知道?
例如,跳过before_filter
可能会减少痛苦,但由于它们是相应的私人方法,我觉得跳过它们是不合适的。
class UsersController < AdminController
before_filter :check_auth
before_filter :check_admin
around_filter :set_tenant_time_zone, if: current_tenant
def index
Kaminari.paginate(current_tenant.users).page(params[:page])
end
private
def current_user
# gets user from session
end
def current_tenant
current_user.tenant if current_user
end
def set_tenant_time_zone
Time.use_zone(current_tenant.time_zone, &block)
end
def check_auth
redirect_to login_url unless AuthChecker.new(current_user, request.remote_ip).has_access?
end
def check_admin
redirect_to root_url unless current_user.is_admin?
end
end
答案 0 :(得分:1)
如果你想运行那些before_filters,你必须做所有那些模拟/存根但是我认为,对于那些情况,最好使用一些规范帮助方法来创建一个登录用户,因此,根据你的规范,你只需要在&#34;之前调用该方法(:每个)&#34;您想要用户的控制器块。
在spec_helper.rb中:
def current_user(stubs = {})
unless @current_user
u = FactoryGirl.build(:user, stubs)
u.save(:validate => false)
@current_user = u
end
@current_user
end
def current_user_session(stubs = {}, user_stubs = {})
@current_session ||= mock_model("Session", {:record => nil, :user => current_user(user_stubs)}.merge(stubs))
end
def login(session_stubs = {}, user_stubs = {})
UserSession.stub(:find).and_return(current_user_session(session_stubs, user_stubs))
controller.stub(:current_user => @current_user)
end
所以,在需要登录用户的控制器规范上我可以做一些特殊的存根
describe 'GET index' do
before(:each) do
login #this does all you need to pass the filters
end
it 'does something' do
current_user.stub(:some_method)
get :index
expect(response).to something
end
end
那样测试只有操作的实际代码的存根,实例和期望而不是过滤器