Spies with Sinon

Codecademy Team
Step aside, James Bond! In this article, you'll learn about spies in the context of testing and about the Sinon.js library.

What are Spies?

In testing, a spy is a function that observes and records information about another function’s calls including arguments, return value, the this value, and exceptions thrown (if any). The information that is observed by the spy can then be used in assertions for testing.

As an example, let’s say we are testing a top-secret application with a feature to receive a message, display for 5 seconds, then delete it. We can wrap a spy around this unit to keep track of how many messages were received, what the messages said, if any errors were thrown, etc. Using its stealthy powers of espionage, a spy won’t change anything about how the function operates, it will just observe what happens.

What is Sinon?

Sinon.js is a JavaScript library that includes standalone fakes, spies, and mocks that can be used in any unit testing framework. The Sinon spies documentation highlights the different information that can be pulled from spies.

How to Spy?

There are multiple ways to use a spy, they can be anonymous functions or they can wrap around existing methods in a program. You can see all the many ways to use spies in the Sinon spies documentation, but we’ll focus on one type in particular: wrapping methods.

Our spy will be wrapped around a method and, as we use the method in our tests, will observe everything that happens involving that method. We can think of a spy with a wiretap, taking notes on every interaction that method has.

The following example demonstrates some basics of using the sinon.spy() method to test the method of an object.

const robot = {
greet(name){ // Unit being tested
return 'Hello ' + name;
}
};
test('greet should return hello codey', () => {
sinon.spy(robot, 'greet'); // Initialize the spy
robot.greet('codey'); // Call the method
expect(robot.greet.called).to.be.true;
expect(robot.greet.calledWith('codey')).to.be.true;
expect(robot.greet.returned('Hello codey')).to.be.true;
robot.greet.restore(); // Remove spy from wrapped method
});

In the example above, the sinon.spy() method is used to wrap the robot object’s .greet() method. Doing so adds a number of useful properties and methods that allow us to monitor its behavior after we call robot.greet('codey'). Using a few of these methods, we test if the .greet() method…

  • has been called using the .called property
  • is called with the correct argument using the .calledWith() method
  • returns what we expect it to return using the .returned() property

Finally, to ensure that the method returns to its original, un-spied-on state, we use the .restore() method.

There are too many properties and methods available to spied-on functions to cover in one article and even to commit to memory, so we recommend that you check out the documentation to find the right tools for your needs.

Summary

Spies are an incredibly useful tool that serves as a means for observing and recording information about how our methods are used in tests. Though there are a number of JavaScript libraries that provide spying functionality, Sinon.js is well known and used widely, including at Codecademy!