Learn about the differences between anonymous stubs and stubs in Sinon.JS that wrap existing objects to modify behavior, and then replace a debugger using proxyquire with an anonymous stub.
- [Instructor] Stubs are fantastic for giving complete control over the response from a dependency. Sinon's implementation of stubs matches the academic definition pretty closely. A stub can be used to control a method's behavior in whatever arbitrary way you want. This includes preventing the method in question from being called. Stubs can be anonymous, meaning created with no existing behavior. They can also wrap an existing object to allow selective modification of components, like replacing just one method with a stub.
By default, a stub's response is undefined, which means it does nothing when you call it. Nowhere, as in nothing returned. How are we going to use anonymous stubs in testing our application? First, we're going to use an anonymous stub to disable the debugger. I'll admit, this is kind of arbitrary because we're going to set an environmental variable to enable it, then remove it with a stub, but it's a good way to demonstrate how the system works. Let's switch over to Atom.
In the tree view, open package.json. Modify the test script to set an environmental variable using cross-env, which should work on both Mac and Windows. We're going to set debug equals nadia:* and then space and mocha. Save the file, then close package.json and open up the terminal. Let's run the test suite, NPM test.
If we scroll up, we can see two debug statements from the validate function. That's sub optimal, so let's get rid of that. In the tree view, navigate to test, unit, lib, and open reservations.js. At the top of the file, we're going to need to require two modules. The first is const proxyquire equals require proxyquire, and the second is Sinon for the test doubles, so const Sinon equals require Sinon.
We're going to be replacing the require for reservations with proxyquire, so delete the existing one. The next thing we'll need to do is create the stub. We're going to set it up right at the beginning of the reservations library so it can be reused in each test. Make sure we're in the reservations library, then, since debug is initialized by passing the name of what's being debugged to a function, we're going to start off with a function, so const debugStub equals function.
All the function is going to do is return a new stub, Sinon.stub. That's all we need for the stub itself. We'll also create the reservations variable, which will be the target for proxyquire. Let reservations. Now that the stub is created, we'll do the override for reservations for every test in the suite. Using a mocha before, so before and then function, set reservations to proxyquire, the same path as the original require, dot dot, dot dot, dot dot, to lib reservations, and then pass it in an object.
The format is the name of the module being overwritten as the key, and the value is the test double. In our case, debug is the module and debugStub is the double. Remember the semicolons, and then save the changes. Let's run the test with our new configuration. From the terminal, type NPM test. All the tests should continue to pass, but this time, the debugger should be silenced.
Using an anonymous stub as a portable black hole is useful, but what about custom responses for existing methods?
- What is code quality?
- Testing and code quality fundamentals
- Coding conventions and standards
- Creating and enforcing coding standards
- Unit, integration, and functional testing
- Test-driven development test specificatons
- Behavior-driven development test specifications
- Finding errors with linting
- Extending an ESLint shareable config
- Validating correctness with unit testing
- Replacing and inspecting with stubs, spies, and mocks
- Code coverage and why it matters
- Coverage with continuous integration