3

在为控制器编写功能测试时,我遇到了这样一个场景,我有一个 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 站点很容易,因此它存在于数据库中,但正如我之前所说,我想减少数据库的使用以帮助保持我的测试速度。

4

2 回答 2

1

尝试将 'Site.first' 存根,因为它是您需要存根的 @site var 的设置,而不是 before_filter 返回的 var。

于 2010-10-04T21:34:39.590 回答
0

你的原因@sitenil因为你load_site_from_subdomain做了值赋值@site- 它不返回任何值,因此你的存根load_site_from_subdomain根本没有将值赋值给@site. 有两种解决方法:

第一种方式:

改为只做load_site_from_subdomain一个返回值:

def load_site_from_subdomain
  Site.first(:conditions => { :subdomain => request.subdomain })
end

然后删除before_filter :load_site_from_subdomain并将您的更改show为:

def show
  @site = load_site_from_subdomain
  @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

然后在测试中进行存根:

@controller.stubs(:load_site_from_subdomain).returns(@site)

确保我们@site的间接通过load_site_from_subdomain

第二种方式

Site.first要存根respond. 无论如何,如果你想走这条路,你可以在你的测试中把它存根:

Site.stubs(:first).returns(@site)
于 2012-10-24T22:44:04.490 回答