Adding code coverage

Now that our test suite is working and has one test, let's introduce code coverage. Adding this from the beginning of development is very easy and will help us focus on parts of the code that need to be tested, especially some use cases that involve specific conditions (such as if-then-else statements in our code). Having it all set up from the start of development is easy. On the other hand, if you have a fully working code and want to add tests and coverage, it will be harder and will take quite some time.

To add code coverage, we'll introduce another module. We'll install it globally to be able to run the tests with it directly:

npm install -g nyc

We can now run our tests with the following instrumentation:

nyc npm test

This should run our tests with the instrumentation installed. In the end, you'll get a nice console report.

The coverage results are stored inside in a .nyc_output folder. This enables you to look at the last test results without running tests again. This is useful if your test suite is big and takes some time to finish.

To see the results, you just run nyc report:

The result is a console report. There are several other styles of reports. One particularly useful one is the html report. Let's generate it:

nyc report --reporter=html

You should now have a coverage folder with an index.html file. Open that in your browser, and you should see something like the following screenshot:

We only have one file that represents our microservice. If we had more, they would be listed hierarchically. There are global average statistics for every file.

There are three important groups of columns:

  • Statements: Which represent code statements (conditions, assignments, assertions, calls, and so on)
  • Branches: Which represent possible code control workflows, such as if-then-else or switch-case statement possibilities
  • Functions: Which represent our actual code functions and callbacks

You can click in our file, look at the specific details of it and, more specifically, see the code and information line by line:

To the right of every line number, you see a gray area and, in this case, you see 2x in some of the lines. This is the execution count for that line. The execution has passed by that line twice. This is actually not that important, unless you're looking for bits of code that get largely executed and you want to do some kind of optimization.

You can also see that line 12 has two changes. First, there's a pinkish background in the back of throw err. That means that statement never got executed, which is normal for now as we always successfully connected to the database. The mark before the if statement means that the condition never got executed:

If you scroll a few lines down, we'll see more lines with marks. For example, we can see our image upload method got almost completely covered. The only statement missing is the error handling.

As we delete our test image before running the tests, our image deletion method is also covered. Again, the only missing branch is if the database returns an error to our DELETE query.

Before going any further with the image upload, let's add another integration test file called image-parameter.js, and add some tests to increase our coverage:

const chai = require("chai");
const http = require("chai-http");
const tools = require("../tools");

chai.use(http);

describe("The image parameter", () => {
beforeEach((done) => {
chai
.request(tools.service)
.delete("/uploads/test_image_parameter.png")
.end(() => {
return done();
});
});

it("should reply 403 for non image extension", (done) => {
chai
.request(tools.service)
.get("/uploads/test_image_parameter.txt")
.end((err, res) => {
chai.expect(res).to.have.status(403);

return done();
});
});

it("should reply 404 for non image existence", (done) => {
chai
.request(tools.service)
.get("/uploads/test_image_parameter.png")
.end((err, res) => {
chai.expect(res).to.have.status(404);

return done();
});
});
});

Let's run our test suite and see how it goes:

Refresh the HTML report page and look at our parameter method:

As you can see, we now cover the following condition:

if (!image.match(/.(png|jpg)$/i)) {

The following condition:

if (err || !images.length) {

We now have full coverage on this method.

There are other coverage lines that are harder to test, such as timers (you can see one on line 28), catch statements, or external errors coming from databases or other storage sources. There are ways of mocking those events, and we'll cover them later on.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset