测试:是否使用Stub模型方法



我做两种测试:单元测试和集成测试(后者是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

根据定义,单元测试是测试单个代码单元。如果你不是在嘲笑/剔除问题,那么你真的在测试一个单元吗?还是在运行一个小型集成测试?最佳实践是为您的单元测试进行Mock/Stub

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

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

把它想象成一种假设。如果你假设你的方法正在工作,因为你对该方法的单元测试正在工作,并且其他工作都基于这个假设,那么一切都会好起来,直到这个假设被证明是错误的。在那一刻,一切都崩溃了。另一方面,如果你认为该方法是错误的,而是用已知结果替换它(即模拟方法给出固定结果),那么你的其他代码就与该问题无关。

在单元测试中,您可以在测试PriceLister时从Price中截取方法。您应该对Price方法进行单独的单元测试。

您的集成测试应该是测试整个终端功能,而不需要存根任何

最新更新