如何在node.js中使用伊斯坦布尔增加代码覆盖率

时间:2018-09-18 04:54:09

标签: javascript node.js unit-testing mocha istanbul

我使用Istanbul进行代码覆盖,但是覆盖率却很低,尤其是在Models文件中。

考虑以下是模型文件:

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();
            });
        });
    });

但是我得到的是代码覆盖率20。所以我如何增加百分比:

也:

1。如果需要,我是否必须嘲笑db.connectDatabase

  1. 是否必须使用TestDb运行所有UnitTest?还是我必须assert ??

  2. 代码覆盖率将适用于单元测试或集成测试?

请分享您的想法。谢谢

1 个答案:

答案 0 :(得分:0)

我一直在使用Istanbul来100%的代码覆盖我的大多数客户端/服务器项目,因此我可能会找到您要的答案。

工作方式

每当您需要一些本地文件时,它就会被包装在各处,以了解您的代码是否可以访问其每个部分。

不仅需要的文件被污染,您的运行测试也受到污染。 但是,尽管很容易编写代码来覆盖正在运行的测试文件,但是模拟类及其代码可能永远不会执行。

todoMock.expects('save')

根据Sinon documentation

  

使用模拟函数覆盖todo. save并返回它。

如果Istanbul污染了真实的save方法,那么就不会达到该范围内的任何值,因此您实际上是在测试该模拟程序是否有效,而不是您的真实代码有效。

这应该回答您的问题:代码覆盖率将适用于单元测试或集成测试?

答案是它涵盖了代码,从代码覆盖的角度来看,这是您唯一感兴趣的内容。覆盖Sinon JS并不是没有目标。

无需断言...但是

一旦您了解了Istanbul的工作原理,它就会自然而然地了解,无论您是否assert都没有关系,重要的是您可以获取真实的代码和执行它。

声明只是预防失败的方法,并不是任何Istanbul测试中本身有趣的机制。当您的断言失败时,您的测试也将执行,因此,让您知道事情不正常,并且无需继续测试其余代码(早期失败,更快的修复程序)对您很有帮助。

是否必须模拟db.connectDatabase

是的,至少对于您发布的代码。您可以将db作为通用对象模拟物分配给global上下文和expect方法以进行调用,但是您也可以通过编写以下代码简化您的工作:

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);

您可以使用测试文件中的此代码创建全局db,该行为在传递的错误数量上会相应地表现不同,从而使您能够以不同的期望多次运行同一测试文件。

如何多次运行同一测试

测试完成后,先delete require.cache[require.resolve('../test/file')],然后再require('../test/file')

根据需要执行多次。

有条件特征检测时

我通常会多次运行测试,以删除全局构造函数,以防它们带有后备补丁。我通常还会存储它们,以便以后将它们放回原处。

当代码很明显但不应到达

如果您有if (err) process.exit(1);,则很少希望到达代码的那部分。 Istanbul可以理解各种注释,这些注释可以帮助您跳过部分测试,例如/* istanbul ignore if */ignore else,甚至通用的ignore next

请考虑三思,如果只是您是懒惰,还是真的可以安全地跳过那一部分……我被错误处理的问题咬了好几次,这是灾难,因为发生的时间是您需要最多的代码来保持运行和/或为您提供所需的所有信息。

涵盖了什么?

也许您已经知道这一点,但是可以立即使用任何浏览器打开的coverage/lcov-report/index.html文件将向您显示测试中未涵盖的所有部分。