【问题标题】:Stub private controller methods in Rails / RSpecRails / RSpec中的存根私有控制器方法
【发布时间】:2014-10-03 06:12:30
【问题描述】:

这个简单的测试有问题:

book_spec.rb

let(:books_controller) { BooksController.new }

context "GET #index" do
  it "calls Book.all" do
    Book.should_receive(:all)
    book_controller.index
  end
end

books_controller.rb

def index
  respond_with books
end

private

def books
  @books ||= Book.all
end

我想删除对 ActiveRecord 的调用,这样它就不需要与数据库交互并加快测试速度。但是,我似乎无法做到这一点。

编辑:

抱歉忘记了最重要的一点!

 Failure/Error: book_controller.index
 NoMethodError:
   undefined method `variant' for nil:NilClass

【问题讨论】:

  • 有什么问题?您收到错误、失败的测试或测试触发对 DB 的请求?
  • @gotva 抱歉,包含错误消息。
  • hmmm... Google 返回了很多建议。我认为this one 与您的问题非常相似,主要思想是You can't test controllers like this due to how the Rails application life cycle works.。在那里写“经典”控制器规范和存根Book.all 怎么样。

标签: ruby-on-rails rspec mocking


【解决方案1】:

在 Rails 中通过实例化控制器来测试控制器会很困难。大多数控制器测试使用 Rspec 的 get 方法调用控制器操作。尝试类似:

context "GET #index" do
  it "calls Book.all" do
    expect(Book).to receive(:all)
    get :index
  end
end

如果您真的不想接触 ActiveRecord,那么您可以通过将测试更改为以下内容来存根 Book

let(:book) { double(:book, all: true) }

context "GET #index" do
  it "calls Book.all" do
    stub_const("Book", book) 
    expect(Book).to receive(:all)
    get :index
  end
end

但是,我认为尝试在此处存根活动记录不会大大提高速度。在运行测试时加载 Rails 环境是最大的时间开销——尤其是对于小型测试套件。

【讨论】:

  • 非常感谢第一个解决方案有效,第二个没试过。我将不得不与团队讨论如何消除 AR。
  • #find 方法怎么样。我只是尝试编写一个测试并使用了请求get :show,但它不起作用。但是get :show, :id => 1 有效。 1 显然是硬编码的。通常我会做id => @book.id 但是这里没有@book。有什么想法吗?
  • 您可以创建一个新的 Book 实例并将其分配给 @book(可能使用 FactoryGirl),然后调用 get :show, id: @book.id。或者,您可以使用带有任意 ID 的双精度。
猜你喜欢
  • 1970-01-01
  • 2013-07-28
  • 2011-05-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多