JS: Advanced Testing
Theory: Testing HTTP Requests
Dependency inversion is an extremely powerful technique that works not only with functions, but also with objects. Let's take a deeper look at it using HTTP requests as an example, and get acquainted with the notion of a stub.
Suppose we have a function that parses an organization's private repositories on GitHub and returns the ones that are forks (i.e., split off from the main directory):
Let's test it. What do we want from this feature? First of all, we need to make sure that it works correctly, i.e., that it returns an array of private forks. An ideal test would look like this:
Unfortunately, it's not that simple. An HTTP request is made inside the function. Let's see what kind of problems this can cause:
- An unstable network can slow down test execution and lead to phantom errors. The tests will sometimes past, and sometimes not.
- Services like github.com have limits on requests per second, per hour, per day, and so on. It's guaranteed that the tests will begin to stall at these limits. Moreover, there's a chance that the machine that the requests come from will be blocked.
- The actual data on GitHub isn't static, it can and probably will change, which again will lead to errors and your tests will need to be fixed.
In this example, the HTTP request is seen as a hindrance to testing our underlying logic. We trust github.com and its @octokit/rest library, which means we don't need to check it works correctly (or you'll go nuts if you don't trust anyone).
In the previous lesson, we learned about several ways out of this situation, this is one instance in which we can apply one of them.
Dependency inversion
In order to use dependency inversion, we add the Octokit client itself as the second argument for the function. This will allow you to substitute it in the tests:
We have to implement a fake client, which behaves similarly to the real Octokit except that it doesn't make any network requests. We also need to describe the specific data that the listForOrg call will return. Only then we can test to see that the getPrivateForksNames() function works correctly.
And the test itself using this client:
When it comes to testing for such fake objects (or functions), we have a special name for them - stubs. A stub replaces a real object or function, avoiding side effects or making the code deterministic. Stubs aren't used to test anything, they only allow you to isolate the part that interferes with testing the underlying logic.
Banning HTTP requests
Another way to avoid HTTP requests from tests is to disable them in tests. In future lessons, we'll get acquainted with the Nock library, which has a method for banning any HTTP requests from the code: nock.disableNetConnect(). We recommend calling it at the beginning of the test file. In addition, it helps to see which pages are being queried by third-party libraries. This is what the output looks like after disabling external connections (assuming that no query spoofing was performed):

