测试:存根模型方法与否?

时间:2013-11-19 21:27:32

标签: ruby-on-rails unit-testing rspec

我做了两种测试:单元测试和集成测试(Cucumber / Capybara用于后者)。

对于单元测试,我想知道在测试其他类时是否最好使用存根/模拟模型方法?

# model
class Price < ActiveRecord::Base
  belongs_to :price_type, inverse_of: :prices
  belongs_to :book, inverse_of: :prices

  scope :for_book, ->(book) { where("book_id = ?", book) }
  scope :for_price_type, ->(price_type) { where("price_type_id = ?", price_type) }

  def self.latest_book_url(book, competitor)
    latest_price = for_book(book).for_competitor(competitor).last
    latest_price ? latest_price.book_url : nil
  end
end

如果我测试一个调用这些范围的类或类方法latest_book_url,我应该模拟/存根模型的范围和方法,还是使用FactoryGirl来保存记录,然后在测试中调用模型上的方法?

# class to be tested
class PriceLister
  def initialize(book)
    @book = book
    @competitors = book.competitors
    @price_types = PriceType.all
  end

  def list_book_urls_by_competitor
    price_list = {}
    @competitors.each do |competitor|
      price_list[competitor] = {}      
      price_list[competitor][:book_url] = Price.latest_book_url(@book, competitor)
      @price_types.each do |price_type|
        price_list[competitor][price_type] = Price.for_book(@book).for_competitor(competitor).for_price_type(price_type).last
      end                
    end
    price_list
  end
end

2 个答案:

答案 0 :(得分:3)

根据定义单元测试是单个代码单元的测试。如果你没有嘲笑/抄袭东西,那么你真的在测试一个单元,还是在进行小型集成测试?最佳做法是Mock / Stub进行单元测试

假设您仍在讨论第二个问题的单元测试,那么您应该现在模拟/删除已经测试过的代码。

原因很简单。如果您更改代码并中断测试,则希望尽可能轻松地缩小导致问题的代码范围。如果你打破了很多测试,因为他们都调用了同一段代码,那么你突然有很多测试需要检查。如果你在所有其他测试中模拟了那个调用,那么只有真正测试该单元的测试才会失败,而不是那些依赖于它的工作正常。

把它想象成一个假设。如果你认为你的方法是有效的,因为你对该方法的单元测试是有效的,并且基于该假设的其他工作,它将一切正常,直到该假设被证明是错误的。那时一切都会崩溃。另一方面,如果你认为该方法是错误的,而是将其替换为已知结果的东西(即模拟方法和固定结果),那么你的其他代码就会与该问题隔离开来。

答案 1 :(得分:1)

在单元测试中,您可以在测试PriceLister时从Price存根方法。您应该为Price方法进行单独的单元测试。

并且您的集成测试应该测试整个端到端功能而不会存在任何障碍