Skip to content

Instantly share code, notes, and snippets.

@quii
Created July 15, 2020 14:45
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save quii/bcf035a8ccf874540fa43b6bfcd0e4f9 to your computer and use it in GitHub Desktop.
Save quii/bcf035a8ccf874540fa43b6bfcd0e4f9 to your computer and use it in GitHub Desktop.

Words are important

Chris James 15 Jul 2020 https://quii.dev

"Mocking"

People say

We mock these dependencies in the test

And also you hear advice that

Too much mocking is bad

One of these statements is definitely true, the other not so much

Quick primer on dependencies

To separate concerns, we often make objects that will “depend” on other objects.

We “inject” or “pass in” these dependencies when we construct them so they can do a job.

This is called Dependency Injection.

Example

A ShoppingCart sends an email when an order is sent.

We don’t want ShoppingCart to have to know how to send emails as well as everything else so we give it an Emailer when we create it.

new ShoppingCart(new MailgunEmailer())

Example

It can then use the emailer without having to know how emails are sent, and you have your separation of concerns.

sendOrder() {
	// interesting domain logic
	this.emailer.send(confirmation)
}

With tests we prefer not to use real objects for dependencies because we want to be able to control them, so we use something different

You use “Test Doubles”

Not specifically mocks

A test double is what you inject into an "object under test" (OUT) to control a dependency.

Like a stunt double!

Using the precise words for test doubles helps reveal intent and documents your design more effectively

It’s not about being big and clever, it helps you communicate unambiguously.

The different kinds of test doubles

Dummies

Sometimes you have arguments to functions that you don’t care about. The arguments you pass in are called “dummies”

const dummyLogger = jest.fn()

Stubs

Some objects will query dependencies for data.

Stub the dependency

const stubUserService = jest.fn(() => 'Miss Jones')

Spies

Sometimes you want to call a method (or more abstractly send a message) to a dependency.

It can be hard to tell in a test that this happened from the outside as it’s an internal detail.

If you want to verify these commands are sent, use a spy.


const spyEmailSender = jest.fn()
 // do some stuff
expect(spyEmailSender.mock.calls.length).toBe(1)

Fakes

Usually a “real” implementation but constrained.

Like an in-memory database.

Not as popular anymore due to things like Docker.

Mocks

Mocks are a kind of test double!

Mocks are precise and encapsulate the detail of your interactions more explicitly.

You describe upfront what calls you expect on your test double

  • Order
  • Arguments
  • Specific return values

If the object under test doesn’t call things as expected the mock will error.

Why “mocking too much is bad”

The risk is your tests become needlessly precise and coupled to implementation detail.

There is also true of spies as they have quite a similar nature.

If you're overly specific with your mocks, when you want to refactor things you may find tests failing for annoying reasons that have nothing to do with behaviour

Why “having too many test doubles is bad”

Listen to your tests if they cause you pain

If you have many test doubles in a test that means your OUT has many dependencies.

Does that sound right to you?

Summary

Correct naming things help you be precise when communicating with other developers.

Tests are supposed to act as documentation so describing your test doubles correctly will help reveal the design of the test for maintainers.

So start naming things correctly, today!

Questions?

Quiz

What does a test with lots of doubles tell you?

How do you fix a test with many test doubles?

Name all the kinds of test doubles

How is a mock different from a spy?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment