Testing with Mocks and Stubs
Objectives
Define a stub
Define a mock
Explain when to use mocks and stubs
Explain when you might want to avoid mocks and stubs
What are stubs?
While spies wrap existing functionality, stubs allow us to replace the functionality completely. The original function won't run anymore, but rather our new stub that simply returns a result. This is especially handy if we want to test async stuff that makes use of things like jQuery's AJAX methods.
For example, let's take a look at this code:
This seems easy enough, but async code like this gets really hard to test. What we'll do instead is stub jQuery's .get()
method — this way it doesn't make any external requests for the purposes of our test. This makes our test a lot faster and super stable.
Using stubs, it's also really easy to test our code for edge cases. What happens when the request fails, or sends back unexpected data? Stubbing the method like this gives us absolute control over the data that is returned through the $.get()
method, making testing for this stuff trivial.
What are mocks?
Mocks are the end-all of fake methods. They're kind of like spies, but they also have stubbed behavior (much like stubs), and contain 'pre-programmed expectations'. That just means that we tell the mock what to expect up front.
Let's assume that we have some kind of storage mechanism that saves a user's preferences:
Now, we have some other code that makes use of this function to save the options in the UI to the storage:
Let's test the sendPrefsToStorage()
method. We'll mock our storage
since we're interested in verifying our function, and not the logic of storage
itself:
As you can see, it's easy to mock both methods on the storage
object using Sinon's mock. However, it is important that we only mock what we actually need. Mocking too much stuff will lead to brittle tests.
Avoiding stubs and mocks
The best kind of code is modular with most of its functions being pure (remember, a pure function is a function that determines its return value only by its input values, without any side-effects). As such, it's easier to test our actual implementations piece by piece rather than relying on stubs and mocks.
Stubs and mocks are still useful for testing the annoying async parts or mocking out methods in a library, but they should be used very sparingly.
Resources
Last updated