Are you new to mock objects? Are you trying to learn how to use them? Are you looking for some “hello world” examples for Mock Objects?
Mock objects can be a really good tool sometimes, but not always. This is a guide, to help you learn how and when you can use them.
In simple words what is a mock object?
A mock object is an object that you will use in place of another one.
When do you want to use a mock object?
Normally you want to use a Mock Object when you want to delegate some functionality to other object but you don’t want to test the real functionality on your current test, so you replace that object with other that is easier to control. Let’s call this object dependency…
So, you use a mock when the code you are testing has a dependency but you don’t want to use the real dependency, you just want to check that you are interacting with that dependency in the right way.
This interaction normally comes in three different flavors. You could want to use that dependency to query for something, to change something or to change something and expect something back.
So at least you should know how to test this interactions.
How you can use a mock object when you want to query for something?
When you are using the dependency to “query” for something, you don’t need to use the “mock API”. You can create a regular object with the expected interface, and test for the expected output in the object that you are testing.
describe "Books catalog" do class FakeDB def initialize(books:) @books = books end def fetch_books @books end end it "has the stored books" do db = FakeDB.new(books: ["Principito"]) catalog = BooksCatalog.new(db) expect(catalog.books).to eq ["Principito"] end end
How you can use a mock object when you want to change something?
When you want to make a change in your dependency or do something with side effects like inserting a new record on a database, sending an email, make a payment, etc. Instead of testing that the change or side effect was produced, you check that you are calling the right function/method with the right attributes.
describe "Books catalog" do class FakeDB def self.insert(book) end end def db FakeDB end it "stores new added books" do catalog = BooksCatalog.new(db) # This is how you can use the Mock API of rspec expect(db).to receive(:insert).with("Harry Potter") catalog.add_book("Harry Potter") end end
How you can use a mock object when you want to change something and expect something back?
Sometimes you need will expect something back after calling your dependency to change something. For example is common to create a record and expect the created record or the id in return. In this case what you can do is to tell rspec what you expect from the call to your dependency.
describe "Books catalog" do class FakeDB def self.insert(book) end end def db FakeDB end it "returns the id of the created record" do catalog = BooksCatalog.new(db) # This is how you can use rspec to define a response. allow(db).to receive(:insert).and_return(id: "book-1234", name: "Harry Potter") book_id = catalog.add_book("Harry Potter") expect(book_id).to eq "book-1234" end end
These are some basic examples, and in some cases you are going to need something more complex, but really you can do a lot just with this knowledge =)