简体   繁体   中英

Unit testing a model method in Rails using MiniTest - How to use stubs or mock objects?

I am learning on Rails 3 and I started to to unit testing. After some research I decided to use MiniTest for unit testing.

I have the following model

class Participant < ActiveRecord::Base

  ...

  # returns all items that were paid by participant  
  def paid_expenses
    self.items.where(:payee_id => self.id)
  end

  ...

end

I'm still in the process of figuring out how to unit test that method. I came up with the test case below.

class TestParticipant < MiniTest::Unit::TestCase

  def setup
    @participant = Participant.new
    @participant.first_name = "Elyasin"
    @participant.last_name = "Shaladi"
    @participant.email = "Elyasin.Shaladi@come-malaka.org"
    @participant.event_id = 1  
  end

  ...

  def test_paid_expenses
    @participant.save!
    item1 = @participant.items.create!( item_date: Date.today, amount: 10, currency: "EUR", exchange_rate: 1, base_amount: 10, payee_id: @participant.id, payee_name: @participant.name )
    item2 = Item.create!( item_date: Date.today, amount: 99, currency: "EUR", exchange_rate: 1, base_amount: 10, payee_id: 99, payee_name: "Other participant" )
    assert_includes @participant.paid_expenses, item1, "Participant's paid expenses should include items paid by himself/herself"
    refute_includes @participant.paid_expenses, item2, "Participant's paid expenses should only include items paid by himself/herself"  
  end

  ...

end

That's how far I got, but I don't feel satisfied really. I have the feeling that I could do better than that. I rely on Item object here, but theoretically in unit testing I should not rely on external factors. I thought "stub", "mock", etc. but cannot see how to approach that properly :-(

Do you see a better way to do that? How could I do this using stubs or mock objects?

I started to practice the assumption that a unit test should test a model/function isolated from external factors. So I decided to stub external behavior not inherent to the model. The unit test for the method of the Participant model could look like this.

def test_paid_expense_items
  item1 = MiniTest::Mock.new
  items = MiniTest::Mock.new
  items.expect :where, [item1], [Hash]
  @participant.stub :items, items do
    assert_includes @participant.paid_expense_items, item1, "Participant's paid expenses should include items paid by himself/herself"
  end
end

So far I'm happy with that solution. However feel free to comment if you think you have a better solution or complementary information or any other contribution.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM