Testing: Stub model methods or not?

migu

I do two kinds of tests: unit tests and integration tests (Cucumber/Capybara for the latter).

For unit testing, I wonder whether it's best practice to stub/mock methods of models when testing other classes?

# 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

If I test a class that calls these scopes or the class method latest_book_url, should I mock/stub scopes and methods of the model or use FactoryGirl to save records and then call the methods on the model in the test?

# 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
AlSki

By definition Unit testing is the tesing of a single Unit of code. If you aren't mocking/stubbing things out, then are you really testing a single unit or are you running a small integration test? The best practice is to Mock/Stub for your unit tests

Assuming that you are still talking about unit testing for your second question, then Yes, you should now mock/stub out the code that you have already tested.

The reasons for this are quite simple. If you change your code and break tests, you want to narrow down the code that caused the problem as easily as possible. If you have broken many tests because they all call the same piece of code, then suddenly you have many tests to check out. If you mocked out that call throughout all your other tests then only the tests that really test that unit will fail, not the ones that depend on it working correctly.

Think of it like an assumption. If you assume your method is working, because your unit tests for that method are working, and base other work on that assumption, it will be all fine, until that assumption is proven wrong. At that point everything falls over. If on the other hand you assume that the method will be wrong and instead replace it with something that is a known result (i.e. a mocked method givne a fixed result) then your other code is isolated from that problem.

Collected from the Internet

Please contact [email protected] to delete if infringement.

edited at
0

Comments

0 comments
Login to comment

Related