Skip to content

Instantly share code, notes, and snippets.

@mlovic
Last active June 1, 2020 16:24
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save mlovic/325f5036b11107dd0b8a to your computer and use it in GitHub Desktop.
Save mlovic/325f5036b11107dd0b8a to your computer and use it in GitHub Desktop.
Difference between mocks and stubs using ruby with mocha library

This gist aims to explain the difference between stubs and mocks and when each should be used. For an introduction to stubs and mocks, start somewhere else, like here.

 

  • Stub: used to isolate the object under test from its dependencies, preventing the test from being influenced by code outside the object. This way the test can't be made to fail or be broken by code which is not part of the specific functionality being tested. Stubs also lead to less code being run, which helps keep tests fast. A stub has no expectations. It doesn't care if it is called or how many times.

    For example, you might stub out a message sent to a database connection if all you are trying to test is the type of the method's return value.

 

  • Mock: used to test outgoing messages. Like a stub, a mock also isolates the object under test by providing a canned answer. The mock, however, does care that the message is being sent, presumably because this message triggers a change of state outside of the sending object. that is exactly what you are trying to test by using a mock.

    You would use a mock to verify that the method being tested makes the appropriate call to the database (apart from returning the correct object).

 

This is why we say that stubs are for testing state, while mocks are for testing behaviour. Stubs merely provide canned answers to method calls in the function. This isolates the object under test, preventing the return value from being influenced by any external objects (dependencies). They aren't concerned with how the method works (behaviour), but only with the result (state). Mocks are concerned with the "how". Mocks set expectations on which methods are called, how many times, and with which arguments. Stubs set no expectations. That is also why mocks can make tests fail and stubs cannot.

 

Example using the mocha library to test the following User.create method

class User
  def self.create(name)
    if UserDB.insert(name)
      user = new(name)
      return user
    end
  end
end

# Tests User.create method

  # STUB  (Reason: we don't want any code from UserDB to interfere with this test.)
  def test_returns_instance_of_User
    UserDB.stubs(:insert).returns(true)  
    # Always return a new user object when message "insert" is sent to UserDB.
    # This prevents any code from UserDB from actually running.

    user = User.create("John")
    assert(user.instance_of? User)
 end
  
  # MOCK  (Reason: we want verify that the method talks to the database.)
  def test_makes_call_to_database_passing_name_as_argument
    UserDB.expects(:insert).with("John").returns(true)
    # Expect message "insert" to be sent to UserDB with argument "John".
    # If this doesn't happen, the test will fail.
    
    User.create("John")
   end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment