首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >基于Model.create的RSpec测试控制器

基于Model.create的RSpec测试控制器
EN

Stack Overflow用户
提问于 2012-08-04 07:13:12
回答 3查看 2.4K关注 0票数 0

我正在尝试测试一个控制器,以确保只有授权方可以使用RSpec查看正确的子对象。我不知道我做错了什么,因为我得到了这个错误:

代码语言:javascript
运行
复制
ActiveRecord::RecordInvalid: Validation failed: Company can't be blank

我有一个Plan对象和一个Company对象。商店可以有很多计划(想一想虫害控制公司)。我想测试一下,给定一个已知的场景,我可以检索到公司的计划(假设只有一个)。

该计划如下所示:

代码语言:javascript
运行
复制
class Plan < ActiveRecord::Base
  before_save :default_values

  # Validation
  validates :amount, :presence => true
  validates :company, :presence => true

  # Plans belong to a particular company.
  belongs_to :company, :autosave => true    

  scope :find_all_plans_for_company, lambda {
    |company| where(:company_id => company.id)
  }
  # Other code ...

end 

公司看起来是这样的:

代码语言:javascript
运行
复制
class Company < ActiveRecord::Base
  validates :name, :presence => true
  validates :phone1, :presence => true

  validates_format_of :phone1, :phone2,
                      :with => /^[\(\)0-9\- \+\.]{10,20}$/,
                      :message => "Invalid phone number, must be 10 digits. e.g. - 415-555-1212",
                      :allow_blank => true,
                      :allow_nil => true

  has_many :users
  has_many :plans

end

。。控制器看起来像这样

代码语言:javascript
运行
复制
def index
    @plans = Plan.find_all_plans_for_company(current_user.company)

    respond_to do |format|
      format.html # index.html.erb
      format.json { render json: @plans }
    end
  end

。。我的RSpec测试看起来是这样的(请原谅,如果它充满了花招,我只是在浪费时间,无法让它正常工作)。

代码语言:javascript
运行
复制
describe PlansController do

  def valid_attributes
    {
        :company_id => 1,
        :amount => 1000
    }
  end

  describe "GET index" do
    it "should return the Plans for which this users company has" do

      @company = mock_model(Company, :id => 1, :name => "Test Company", :phone1 => "555-121-1212")
      Company.stub(:find).with(@company.id).and_return(@company)

      controller.stub_chain(:current_user, :company).and_return(@company)

      plan = Plan.create! valid_attributes

      get :index, {}
      assigns(:plans).should eq([plan])
    end

    # Other tests ...
  end

end

问题是,当我尝试这个(或者我尝试过的任何疯狂的其他变体)时,我得到了这个错误:

代码语言:javascript
运行
复制
ActiveRecord::RecordInvalid: Validation failed: Company can't be blank

我不确定为什么会发生这种情况,因为我认为Company.stub调用会为我处理这个问题。但显然不是。

我在这里遗漏了什么,我做错了什么?我怎样才能让这个测试通过呢?

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2012-08-04 13:31:27

让我们剥离这个规范的层次,以确保它有意义(并确保我理解正在发生的事情)。首先,你在测试什么?

代码语言:javascript
运行
复制
it "should return the Plans for which this users company has" do

  ...

  assigns(:plans).should eq([plan])

因此,您需要检查与当前用户的公司关联的计划是否已分配给@plans。我们可以清除或模拟所有其他的东西。

看一下控制器代码,我们有:

代码语言:javascript
运行
复制
def index
  @plans = Plan.find_all_plans_for_company(current_user.company)

我们需要什么才能让它在不影响数据库和不依赖于模型的情况下工作?

首先,我们想从current_user.company中获得一个模拟的company。规范代码中的这两行代码的作用如下:

代码语言:javascript
运行
复制
  @company = mock_model(Company, :id => 1, :name => "Test Company", :phone1 => "555-121-1212")
  controller.stub_chain(:current_user, :company).and_return(@company)

这将导致current_user.company返回模拟模型@company。到目前一切尚好。

现在来看类方法find_all_plans_for_company。这就是我有点困惑的地方。在您的规范中,您将存根Company上的find方法,以便为id = 1返回@company

但实际上,仅仅在控制器代码中做这样的事情还不够吗?:

代码语言:javascript
运行
复制
  @plans = current_user.company.plans

如果你是这样做的,那么在你的测试中,你只需要模拟一个计划,然后将它作为模拟公司的plans关联返回:

代码语言:javascript
运行
复制
  @plan = mock_model(Plan)
  @company = mock_model(Company, :plans => [ @plan ])
  controller.stub_chain(:current_user, :company).and_return(@company)

然后赋值应该可以工作,并且您不需要实际创建任何模型或访问数据库。您甚至不需要为您的模拟公司提供id或任何其他属性,这些属性无论如何都与规范无关。

也许我在这里遗漏了什么,如果是这样,请让我知道。

票数 2
EN

Stack Overflow用户

发布于 2012-08-04 14:11:37

你为什么需要嘲笑?

我的标准测试设置是使用Database Cleaner,它从测试期间创建的任何记录中清除数据库。以这种方式,测试使用真实数据库记录运行,这些记录随后在每次测试后从测试数据库中删除。

您可能还想看看Factory Girl在测试期间创建模型实例的过程(例如,它可以轻松地创建10个公司记录)。

请参见:

  • http://rubygems.org/gems/database_cleaner
  • http://rubygems.org/gems/factory_girl
票数 1
EN

Stack Overflow用户

发布于 2012-08-04 07:22:51

我有三个想法可以解决你的问题:

  1. 尝试将attr_accessible :company_id添加到计划类。
  2. 当您在company_id为1的情况下创建计划时,由于mock_model实际上不会保存到数据库中,因此验证失败,因为它不存在于计划类中的company_id before_save :default_values中不会影响新创建的实例的company_id属性。
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/11804448

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档