JS: Advanced Testing
Theory: Monkey patching
In the previous lesson, we tested the hypothetical getPrivateForksNames(org) function by applying dependency inversion. Let's remind ourselves of the contents of this function in its original form:
In some situations, dependency inversion is a perfect solution, in others, it makes the code much more complicated and sometimes confusing, especially if the dependencies are needed somewhere deep in the call stack (since you have to pass the dependency through all intermediate functions). But there is a way to get to the right calls and change them, without even using dependency inversion.
The JS prototype model allows you to change the behavior of objects without directly accessing them. To do this, just replace the methods in the prototype. After that, any object that has this prototype in any part of the program will start using the new implementation of the method.
When an object (such as a constructor function) is used directly, it's even simpler than with a construction. It's sufficient to change the property of the object itself:
This approach, where property values are globally swapped, is called (monkey patching). It's considered bad practice when writing regular code in JS, but it is very popular and handy in tests.
The most famous example in the JavaScript world is the nock library. It overrides real network requests made by the http module, which is included in the standard Node.js library.
Nock replaces some of the methods inside the http module that are used by different libraries to make HTTP requests.
And an example of how to use it:
The chain nock(domain).get(urn) specifies the full address of the page you want to intercept. Nock analyzes all running requests and substitutes only the one that matches the given parameters. The domain and page address can be specified as a whole or through a regular expression, you don't have to write too much.
The method reply(code, body, headers) reply(code, body, headers) defines the response to be returned by the given request. In the simplest case, it's enough to specify the return code. In our situation, we need both code and data. This is the data we use to test the function getPrivateForkNames().
Here we've looked at only the most basic use of Nock. This library has a massive amount of documentation and many use cases. It's useful to review it periodically to find more elegant ways to solve testing problems.
What are the pros and cons of this way of working?
The main advantage is that this way of testing is almost universal. It can be used with any code, and you don't need to edit the code itself. The program won't even know it's being tested.
The disadvantage is that black box testing ends up more like “transparent box” testing. This means that the test knows about the structure of the code being tested and depends on the internals. Such knowledge makes the tests fragile. The function can be changed without losing performance, but the tests will have to be rewritten because they're tied to specific values of the domain, pages, and format of the returned data.
In most situations, this isn't so critical. So feel free to use Nock in your projects, but don't forget about other ways.

