-1

I am using Istanbul for code coverage, but i m getting very low coverage percentage particularly in Models file.

Consider the following is the model file:

ModelA.js

const mongoose = require('mongoose');
const Schema = mongoose.Schema;
var app = require('../server')
var db = require('../db/dbConnection');
var config = require('../configs/config')

    const Schema1 = new Schema({ 'configurations': [] });
    exports.save = function (aa, data, callback) {
        var logMeta = {
            file: 'models/modelA',
            function: 'save',
            data: {},
            error: {}
        }    
        if (!aa) {
            return callback('aa is required')
        }
        global.logs[aa].log('info', 'AA: ' + aa, logMeta);   

        db.connectDatabase(aa, function(error, mongoDB){    
            if(error){            
                logMeta.data['error'] = error
                global.logs[aa].log('error', 'error', logMeta);
                return callback(error)
            }

            const ModelA = mongoDB.model('bbb', cccc);                 
            ModelA.findOneAndUpdate({}, data, {upsert: true, new: true, runValidators: true}, function(error ,result){
                if (error) {   
                    logMeta.data['error'] = error
                    global.logs[aa].log('error', 'error', logMeta);
                }
                else {
                    logMeta.data = {}
                    logMeta.data['result'] = JSON.parse(JSON.stringify(result))
                    global.logs[aa].log('info', 'result', logMeta);
                }  
                callback(error, result);    
            });           
        })
    }

TestA.js:

var should = require('should'),
    sinon = require('sinon'),    
    ModelA= require("../models/ModelA");


    describe('Model test', function () {
        it('Should save Model', function (done) {
            var todoMock = sinon.mock(new ModelA({'configurations': []}));
            var todo = todoMock.object;

            todoMock
            .expects('save')
            .yields(null, 'SAVED');

            todo.save(function(err, result) {
                todoMock.verify();
                todoMock.restore();
                should.equal('SAVED', result, "Test fails due to unexpected result")
                done();
            });
        });
    });

But i am getting codecoverage percentage 20. SO how can i increase the percentage:

ALso:

1.Whether i have to mock the db.connectDatabase if yews how can i acheive that?

  1. Whether i have to use TestDb to run all my UnitTest? Or i have to assert??

  2. Code Coverage will work for Unit Test or integration test???

Please share your ideas. Thanks

Subburaj
  • 5,114
  • 10
  • 44
  • 87
  • Consider using **mocha chai**, You can cover 90% of your codes while using chai because you can write test case from your http endpoint. Please take a look following link[https://buddy.works/guides/how-automate-nodejs-unit-tests-with-mocha-chai] – Richardson. M Sep 18 '18 at 05:21
  • @Richardson. M Your link is broken.. – Subburaj Sep 18 '18 at 05:23
  • https://buddy.works/guides/how-automate-nodejs-unit-tests-with-mocha-chai – Richardson. M Sep 18 '18 at 05:24

1 Answers1

1

I have been using Istanbul to 100% code cover most of my client/server projects so I might have the answers you are looking for.

How does it work

Whenever you require some local file, this gets wrapped all over the place to understand if every of its parts is reached by your code.

Not only the required file is tainted, your running test is too. However, while it's easy to code cover the running test file, mocked classes and their code might never be executed.

todoMock.expects('save')

Accordingly to Sinon documentation:

Overrides todo. save with a mock function and returns it.

If Istanbul tainted the real save method, anything within that scope won't ever be reached so that you are actually testing that mock works, not that your real code does.

This should answer your question: Code Coverage will work for Unit Test or integration test ???

The answer is that it covers the code, which is the only thing you're interested from a code cover perspective. Covering Sinon JS is nobody goal.

No need to assert ... but

Once you've understood how Istanbul works, it follows up naturally to understand that it doesn't matter if you assert or not, all it matters is that you reach the code for real and execute it.

Asserting is just your guard against failures, not a mechanism interesting per se in any Istanbul test. When your assertion fails, your test does too, so it's good for you to know that things didn't work and there's no need to keep testing the rest of the code (early failure, faster fixes).

Whether you have to mock the db.connectDatabase

Yes, at least for the code you posted. You can assign db as generic object mock to the global context and expect methods to be called but also you can simplify your life writing this:

function createDB(err1, err2) {
  return {
    connectDatabase(aa, callback) {
      callback(err1, {
        model(name, value) {
          return {
            findOneAndUpdate($0, $1, $3, fn) {
              fn(err2, {any: 'object'});
            }
          };
        }
      });
    }
  };
}

global.db = createDB(null, null);

This code in your test file can be used to create a global db that behaves differently accordingly with the amount of errors you pass along, giving you the ability to run the same test file various times with different expectations.

How to run the same test more than once

Once your test is completed, delete require.cache[require.resolve('../test/file')] and then require('../test/file') again.

Do this as many times as you need.

When there are conditional features detection

I usually run the test various times deleting global constructors in case these are patched with a fallback. I also usually store them to be able to put 'em back later on.

When the code is obvious but shouldn't be reached

In case you have if (err) process.exit(1); you rarely want to reach that part of the code. There are various comments understood by Istanbul that would help you skip parts of the test like /* istanbul ignore if */ or ignore else, or even the generic ignore next.

Please consider thinking twice if it's just you being lazy, or that part can really, safely, be skipped ... I got bitten a couple of times with a badly handled error, which is a disaster since when it happens is when you need the most your code to keep running and/or giving you all the info you need.

What is being covered?

Maybe you know this already but the coverage/lcov-report/index.html file, that you can open right away with any browser, will show you all the parts that aren't covered by your tests.

Andrea Giammarchi
  • 3,038
  • 15
  • 25