在为控制器编写功能测试时,我遇到了这样一个场景,我有一个 before_filter 从数据库中请求我的一个测试需要的一些信息。我正在使用 Factory_girl 生成测试数据,但我想避免在没有明确需要时访问数据库。我还想避免在这里测试我的 before_filter 方法(我计划在单独的测试中测试它)。据我了解,模拟/存根是实现此目的的方法。
我的问题是,在这种情况下模拟/存根此方法的最佳方法是什么。
我的前置过滤器方法根据在 URL 中找到的子域在数据库中查找站点,并设置要在控制器中使用的实例变量:
#application_controller.rb
def load_site_from_subdomain
@site = Site.first(:conditions => { :subdomain => request.subdomain })
end
我的控制器使用此方法作为 before_filter:
# pages_controller.rb
before_filter :load_site_from_subdomain
def show
@page = @site.pages.find_by_id_or_slug(params[:id]).first
respond_to do |format|
format.html { render_themed_template }
format.xml { render :xml => @page }
end
end
如您所见,它依赖于@site
要设置的变量(通过 before_filter)。然而,在测试期间,我想让测试假设@site
已设置,并且它至少有 1 个关联页面(由 找到@site.pages
)。我想load_site_from_subdomain
稍后测试我的方法。
这是我的测试(使用Shouda & Mocha):
context "a GET request to the #show action" do
setup do
@page = Factory(:page)
@site = Factory.build(:site)
# stub out the @page.site method so it doesn't go
# looking in the db for the site record, this is
# used in this test to add a subdomain to the URL
# when requesting the page
@page.stubs(:site).returns(@site)
# this is where I think I should stub the load_site_from_subdomain
# method, so the @site variable will still be set
# in the controller. I'm just not sure how to do that.
@controller.stubs(:load_site_from_subdomain).returns(@site)
@request.host = "#{ @page.site.subdomain }.example.com"
get :show, :id => @page.id
end
should assign_to(:site)
should assign_to(:page)
should respond_with(:success)
end
这让我的测试结果出现错误,告诉我那@site
是零。
我觉得我正在以错误的方式解决这个问题。我知道只需 Factory.create 站点很容易,因此它存在于数据库中,但正如我之前所说,我想减少数据库的使用以帮助保持我的测试速度。