`

assert模块源码

    博客分类:
  • node
 
阅读更多

1.assert断言模块主要解决:

  • 测试需求,提供校验值是否为真、相等/不相等、深度匹配/不匹配等调试方法,不满足校验条件的通过fail函数构造AssertionError对象并抛出。
  • 抛出错误,构造执行函数block,通过block函数抛出错误对象Error,捕获该错误对象,与期望值比较,assert.throw方法中若由block捕获的错误匹配expected期望的校验要求(包括正则、构造函数、以block捕获错误为参数的函数),则既不抛出Error错误,也不抛出AssertionError错误;assert.doesNotThrow方法,若block捕获错误符合期望,抛出AssertionError错误,若不符合,抛出Error错误。

2.assert一般测试方法的构建:

  • 通过assert.throw(block[,error][,message])方法校验block函数执行时捕获的错误是否符合期望error的校验条件,因此该测试方法的实现在于构造block函数。或者重新构建assert方法

3.与jquery-unit的比较:

  • assert模块相等性比较更为细致,还需顾及buffer、ArrayBuffer、DataView对象。
  • 添加一般测试方法,jquery-validate提供了定制校验方法的功能,可以用于多个校验框,jquery-unit也能构造特定的通用的校验方法用于多个测试对象,assert需要反复重写block函数构建,或者重新构建assert方法。

4.使用

  • assert.AssertionError(options) 配置AssertionError错误对象
  • assert.fail(actual, expected, message, operator) 配置AssertionError错误对象,并抛出该错误,actual为实际值,expected为期望值,message错误消息,operater分隔符
  • assert(value, message), assert.ok(value, [message]) 校验value是否为真
  • assert.equal(actual, expected, [message]) 校验两者是否相等==
  • assert.notEqual(actual, expected, [message]) 校验两者是否不相等!=
  • assert.deepEqual(actual, expected, [message]) 数组、对象、时间对象、正则对象、ArrayBuffer对象、arguments对象深度匹配,非严格模式
  • assert.deepStrictEqual(actual, expected, [message]) 数组、对象、时间对象、正则对象、ArrayBuffer对象、arguments对象深度匹配,严格模式
  • assert.notDeepEqual(actual, expected, [message]) 深度匹配返回否值,非严格模式
  • assert.notDeepStrictEqual(actual, expected, [message]) 深度匹配返回否值,严格模式
  • assert.strictEqual(actual, expected, [message]) 相等比较===
  • assert.notStrictEqual(actual, expected, [message]) 不相等比较!==
  • assert.throws(block, [error], [message]) block没有错误抛出AssertionError错误,或者错误不符期望,抛出block捕获的错误
  • assert.doesNotThrow(block, [message]) 没有期望或者block捕获错误符合期望,抛出AssertionError错误;block捕获错误不符合期望,抛出block捕获的错误
  • assert.ifError(value) 参数为Error对象,直接抛出该错误对象

5源码:

'use strict';

// 比较字符串、buffer对象
function compare(a,b){
    if ( a===b ){
      return 0;
    }

    var x=a.length;
    var y=b.length;

    for ( var i=0, len=Math.min(x, y); i<len; ++i ){
        if ( a[i]!==b[i] ){
          x=a[i];
          y=b[i];
          break;
        }
    }

    if ( x<y ){
        return -1;
    }
    if ( y<x ){
        return 1;
    }
    return 0;
}

// 判断是否buffer对象
function isBuffer(b){
    if ( global.Buffer && typeof global.Buffer.isBuffer==='function' ){
      return global.Buffer.isBuffer(b);
    }
    return !!(b!=null && b._isBuffer);
}

var util=require('util/');
var hasOwn=Object.prototype.hasOwnProperty;
var pSlice=Array.prototype.slice;

// 是否拥有函数名
var functionsHaveNames=(function(){
  return function foo(){}.name==='foo';
}());

// 调用toString方法将对象转化为字符串
function pToString(obj){
  return Object.prototype.toString.call(obj);
}

// ArrayBuffer是二进制数据的原始缓冲区,该缓冲区用于存储各种类型化数组的数据
// var buffer=new ArrayBuffer(12);
// var x=new Int32Array(buffer);// 也可以直接创建
//                              // Int8Array 8位二补码有符号整数
//                              // Uint8Array 8位无符号整数
//                              // Int16Array 16位二补码有符号整数
//                              // Uint16Array 16位无符号整数
//                              // Int32Array 32位二补码有符号整数
//                              // Uint32Array 32位无符号整数
//                              // Float32Array 32位 IEEE 浮点数
//                              // Float64Array 64位 IEEE 浮点数
// x[0]=1234;console.log(x[0])  // 1234

// DataView可以对数据作更细致的操作,即每项设置不同的数据类型
// var buffer=new ArrayBuffer(12);
// var x=new DataView(buffer, 0);
// x.setInt8(0, 22);
// x.setFloat32(1, Math.PI);
// console.log(x.getInt8(0)); // 22
// console.log(x.getFloat32(1)); // 3.1415927410125732

// 判断是否ArrayBuffer对象
function isView(arrbuf){
    if ( isBuffer(arrbuf) ){
        return false;
    }
    if ( typeof global.ArrayBuffer!=='function' ){
        return false;
    }
    if ( typeof ArrayBuffer.isView==='function' ){
        return ArrayBuffer.isView(arrbuf);
    }
    if ( !arrbuf ){
        return false;
    }
    if ( arrbuf instanceof DataView ){
        return true;
    }
    if ( arrbuf.buffer && arrbuf.buffer instanceof ArrayBuffer ){
        return true;
    }
    return false;
}

var assert=module.exports=ok;

// 获取函数名
var regex=/\s*function\s+([^\(\s]*)\s*/;
function getName(func){
    if ( !util.isFunction(func) ){
        return;
    }
    if ( functionsHaveNames ){
        return func.name;
    }
    var str=func.toString();
    var match=str.match(regex);
    return match && match[1];
}

// AssertionError形式的错误对象,继承Error错误对象,用于校验失败后抛出
// new assert.AssertionError({ message: message,
//                             actual: actual,
//                             expected: expected })
assert.AssertionError=function AssertionError(options){
    this.name='AssertionError';
    this.actual=options.actual;// 实际值
    this.expected=options.expected;// 期望值
    this.operator=options.operator;// 分割符
    if ( options.message ){
        this.message=options.message;
        this.generatedMessage=false;
    }else{
        this.message=getMessage(this);// 以实际值+operator+期望值的形式构建默认错误消息
        this.generatedMessage=true;
    }

    // 获取错误的堆栈信息
    var stackStartFunction=options.stackStartFunction || fail;
    if ( Error.captureStackTrace ){
        Error.captureStackTrace(this, stackStartFunction);
    }else{
        // non v8 browsers so we can have a stacktrace
        var err=new Error();
        if ( err.stack ){
            var out=err.stack;

            // try to strip useless frames
            var fn_name=getName(stackStartFunction);
            var idx=out.indexOf('\n'+fn_name);
            if ( idx>=0 ){
                // once we have located the function frame
                // we need to strip out everything before it (and its line)
                var next_line=out.indexOf('\n', idx+1);
                out=out.substring(next_line+1);
            }

            this.stack = out;
        }
    }
};

util.inherits(assert.AssertionError, Error);

// 截取字符串
function truncate(s, n) {
    if ( typeof s==='string' ){
        return s.length<n ? s : s.slice(0, n);
    } else {
        return s;
    }
}

// 将对象转化为字符串后输出,或将函数转化为[Function: fnName]的形式
function inspect(something){
    if ( functionsHaveNames || !util.isFunction(something) ){
        return util.inspect(something);// 将任意对象转化成字符串
    }
    var rawname=getName(something);
    var name=rawname ? ': '+rawname : '';
    return '[Function'+name+']';
}

// 以实际值+分割符+期望值的形式构建默认错误消息
function getMessage(self) {
    return truncate(inspect(self.actual), 128)+' '+
           self.operator+' '+
           truncate(inspect(self.expected), 128);
}

// 配置AssertionError的实际值、期望值、错误消息、分割符、堆栈函数,并抛出错误
function fail(actual, expected, message, operator, stackStartFunction){
    throw new assert.AssertionError({
        message: message,
        actual: actual,
        expected: expected,
        operator: operator,
        stackStartFunction: stackStartFunction
    });
}

assert.fail=fail;

// 校验value是否为真
function ok(value, message){
  if (!value) fail(value, true, message, '==', assert.ok);
}
assert.ok=ok;

// 校验实际值和期望值是否相等
assert.equal=function equal(actual, expected, message){
    if ( actual!=expected ) fail(actual, expected, message, '==', assert.equal);
};

// 校验实际值和期望值是否不相等
assert.notEqual=function notEqual(actual, expected, message){
    if ( actual==expected ){
        fail(actual, expected, message, '!=', assert.notEqual);
    }
};

// 对象等深度比较,非严格模式值比较
assert.deepEqual=function deepEqual(actual, expected, message){
    if ( !_deepEqual(actual, expected, false) ){
      fail(actual, expected, message, 'deepEqual', assert.deepEqual);
    }
};

// 对象等深度比较,非严格模式引用地址比较
assert.deepStrictEqual=function deepStrictEqual(actual, expected, message){
    if ( !_deepEqual(actual, expected, true) ){
        fail(actual, expected, message, 'deepStrictEqual', assert.deepStrictEqual);
    }
};

// buffer对象、ArrayBuffer对象、时间对象、正则对象、数组、对象比较
function _deepEqual(actual, expected, strict, memos){
    if ( actual===expected ){
        return true;

    // buffer对象相等比较
    }else if( isBuffer(actual) && isBuffer(expected) ){
        return compare(actual, expected)===0;

    // 时间对象比较
    }else if( util.isDate(actual) && util.isDate(expected) ){
      return actual.getTime()===expected.getTime();

    // 正则对象比较
    }else if( util.isRegExp(actual) && util.isRegExp(expected) ){
        return actual.source===expected.source &&
               actual.global===expected.global &&
               actual.multiline===expected.multiline &&
               actual.lastIndex===expected.lastIndex &&
               actual.ignoreCase===expected.ignoreCase;

    // null值比较,分为严格比较和不严格比较
    }else if( (actual===null || typeof actual!=='object') &&
               (expected===null || typeof expected !== 'object')){
      return strict ? actual===expected : actual==expected;

    // 判断ArrayBuffer对象是否相等
    }else if( isView(actual) && isView(expected) && pToString(actual)===pToString(expected) &&
            !(actual instanceof Float32Array || actual instanceof Float64Array) ){
        return compare(new Uint8Array(actual.buffer),new Uint8Array(expected.buffer))===0;

    }else if( isBuffer(actual)!==isBuffer(expected) ){
        return false;

    }else{
        // 关于memos以及数组相等判断
        memos=memos || {actual: [], expected: []};

        var actualIndex=memos.actual.indexOf(actual);
        if ( actualIndex!==-1 ){
            if ( actualIndex===memos.expected.indexOf(expected) ){
                return true;
            }
        }

        memos.actual.push(actual);
        memos.expected.push(expected);

        return objEquiv(actual, expected, strict, memos);
    }
}

// 是否arguments参数对象
function isArguments(object){
  return Object.prototype.toString.call(object)=='[object Arguments]';
}

// arguments参数对象、对象、null、undefined比较
function objEquiv(a, b, strict, actualVisitedObjects){
    if ( a===null || a===undefined || b===null || b===undefined )
        return false;

    // util.isPrimitive???
    if ( util.isPrimitive(a) || util.isPrimitive(b) )
        return a===b;
    if ( strict && Object.getPrototypeOf(a) !== Object.getPrototypeOf(b) )
        return false;

    // arguments参数对象比较
    var aIsArgs=isArguments(a);
    var bIsArgs=isArguments(b);
    if ( (aIsArgs && !bIsArgs) || (!aIsArgs && bIsArgs) )
        return false;
    if ( aIsArgs ){
        a=pSlice.call(a);
        b=pSlice.call(b);
        return _deepEqual(a,b,strict);
    }

    // 对象比较,先比较键,再比较值
    var ka=objectKeys(a);
    var kb=objectKeys(b);
    var key, i;

    if ( ka.length!==kb.length )
        return false;

    ka.sort();
    kb.sort();
    for ( i=ka.length-1; i>=0; i-- ){
        if ( ka[i]!==kb[i] )
            return false;
    }

    // 递归比较值
    for ( i=ka.length-1; i>=0; i-- ){
        key=ka[i];
        if (!_deepEqual(a[key], b[key], strict, actualVisitedObjects))
            return false;
    }
    return true;
}

// 对象等深度比较,非严格模式值比较
assert.notDeepEqual=function notDeepEqual(actual, expected, message){
    if (_deepEqual(actual, expected, false)) {
        fail(actual, expected, message, 'notDeepEqual', assert.notDeepEqual);
    }
};

// 对象等深度比较,非严格模式引用地址比较
assert.notDeepStrictEqual=notDeepStrictEqual;
function notDeepStrictEqual(actual, expected, message){
    if (_deepEqual(actual, expected, true)) {
        fail(actual, expected, message, 'notDeepStrictEqual', notDeepStrictEqual);
    }
}

// ===相等判断
assert.strictEqual = function strictEqual(actual, expected, message) {
  if (actual !== expected) {
    fail(actual, expected, message, '===', assert.strictEqual);
  }
};

// !==不相等判断
assert.notStrictEqual = function notStrictEqual(actual, expected, message) {
  if (actual === expected) {
    fail(actual, expected, message, '!==', assert.notStrictEqual);
  }
};

// 用正则、是否实例、函数校验由block函数获得的错误actual
function expectedException(actual, expected){
    if ( !actual || !expected ){
        return false;
    }

    // 当block函数抛出错误throw new Error("Wrong value"),捕获后用正则/value/校验该error为真
    if ( Object.prototype.toString.call(expected)=='[object RegExp]' ){
        return expected.test(actual);
    }

    try{
        if ( actual instanceof expected ){
            return true;
        }
    }catch (e){
      // Ignore.  The instanceof check doesn't work for arrow functions.
    }

    if ( Error.isPrototypeOf(expected) ){
        return false;
    }

    return expected.call({}, actual) === true;
}

// 执行block,有错则捕获错误,返回为真,否则为否
function _tryBlock(block){
    var error;
    try {
        block();
    }catch (e){
        error=e;
    }
    return error;
}

// shouldThrow为真时,block没有错误抛出AssertionError错误,或者错误不符期望,抛出block捕获的错误
// shouldThrow为否时,没有期望或者block捕获错误符合期望,抛出AssertionError错误
//                    block捕获错误不符合期望,抛出block捕获的错误
function _throws(shouldThrow, block, expected, message){
    var actual;

    if (typeof block!=='function'){
        throw new TypeError('"block" argument must be a function');
    }

    if ( typeof expected==='string' ){
        message=expected;
        expected=null;
    }

    actual=_tryBlock(block);// 获取错误或undefined

    message=(expected && expected.name ? ' ('+expected.name+').' : '.')+
            (message ? ' '+message : '.');

    if ( shouldThrow && !actual ){
        fail(actual, expected, 'Missing expected exception'+message);
    }

    var userProvidedMessage=typeof message==='string';
    var isUnwantedException=!shouldThrow && util.isError(actual);
    var isUnexpectedException=!shouldThrow && actual && !expected;

    // shouldThrow为否,且actual是期望捕获的错误,用AssertionError的方式抛出错误
    if ( (isUnwantedException && userProvidedMessage && expectedException(actual, expected)) ||
        isUnexpectedException ){
        fail(actual, expected, 'Got unwanted exception'+message);
    }

    // shouldThrow为真,且actual不是期望捕获的错误,或者shouldThrow为否,actual捕获到错误,抛出actual错误
    if ( (shouldThrow && actual && expected && !expectedException(actual, expected)) || 
        (!shouldThrow && actual) ){
        throw actual;
    }
}

// block没有错误抛出AssertionError错误,或者错误不符期望,抛出block捕获的错误
assert.throws=function(block, /*optional*/error, /*optional*/message){
    _throws(true, block, error, message);
};

// 没有期望或者block捕获错误符合期望,抛出AssertionError错误
// block捕获错误不符合期望,抛出block捕获的错误
assert.doesNotThrow=function(block, /*optional*/error, /*optional*/message) {
    _throws(false, block, error, message);
};

// 参数为Error对象,直接抛出该错误对象
assert.ifError=function(err){if (err) throw err;};

// 获取对象的键
var objectKeys=Object.keys || function (obj){
    var keys=[];
    for ( var key in obj ){
      if ( hasOwn.call(obj, key) ) keys.push(key);
    }
    return keys;
};

 

 

 

 

 

分享到:
评论

相关推荐

    assert模块

    在标题提到的"assert模块"中,`assert`语句是其核心部分。它的基本语法是: ```python assert condition, message ``` 这里,`condition`是一个布尔表达式,如果为`False`,则会触发异常;`message`是可选的错误...

    业务异常提示处理 springboot+Assert(自定义断言)

    本项目“业务异常提示处理 springboot+Assert(自定义断言)”着重于利用Spring Boot的特性来构建高效、易维护的业务逻辑,并通过自定义断言提升代码的可读性和可维护性。下面我们将详细探讨这些知识点。 1. **Spring...

    mocha-assert-example:如何使用Mocha和assert来测试Node.js模块

    Assert是Node.js核心模块之一,包含了一系列的断言方法,如`assert.equal()`、`assert.notEqual()`等,用于比较预期值和实际值,如果两者不符,就会抛出错误。例如: ```javascript const assert = require('assert...

    json-path-assert-2.1.0.zip

    "json4s-ast-master"可能是JSON4S AST模块的源代码主分支,包含了构建、测试和使用这个模块的所有必要文件。 开源项目通常会提供清晰的文档、示例代码和测试用例,帮助开发者理解和使用这些工具。在这个压缩包中,...

    uart通信模块verilog代码.zip

    在给定的“uart通信模块verilog代码.zip”压缩包中,包含了一些关键的UART模块和测试平台的源代码文件,接下来将详细介绍这些文件及其相关的知识点。 1. **uart_tx.v**:这是UART的发送模块,负责将并行数据转化为...

    1-assert(断言).pdf

    断言在编程中是一种非常重要的调试工具,尤其是在测试过程中,用于验证代码的预期行为。在Node.js中,`assert`...在Node.js项目中,通过引入`assert`模块,可以轻松地集成这些断言功能,提高代码质量并减少潜在的bug。

    Node.js assert断言原理与用法分析

    Node.js中的assert模块是JavaScript中一个非常重要的测试库,它主要用于编写程序的单元测试。通过断言可以尽早地发现和排查程序中潜在的错误。在Node.js中,assert模块作为核心模块之一,提供了一系列用于测试的断言...

    assert:将Node.js assert.js移植到浏览器

    在Node.js上运行mocha时,可以使用标准的assert模块。 如果您使用此库,则将在浏览器中运行相同的测试。 如何使用 $ bower install https://github.com/Jxck/assert &lt; script src =" assert.js " &gt; &lt;/ ...

    pytest-assert-utils-0.2.1.tar.gz

    5. `src` 或 `pytest_assert_utils` 目录:包含实际的 Python 模块和类。 - `__init__.py`:使目录成为 Python 包。 - `assertion_utils.py` 或类似文件:包含增强的断言函数或类。 6. `tests` 目录:存放测试代码...

    Node.js利用断言模块assert进行单元测试的方法

    最近在用Node写一个实时聊天小应用,其中就用到了单元测试,所以死下面这篇文章主要给大家介绍了关于Node.js利用断言模块assert进行单元测试的方法,文中通过示例代码介绍的非常详细,需要的朋友可以参考借鉴,下面来...

    Python安装RSA模块

    标签“源码”和“工具”提示我们,这个主题可能涉及到查看和理解RSA模块的源代码,以及它作为一个实用工具在实际项目中的应用。通过阅读源码,开发者可以更好地理解RSA算法的工作原理,以便于自定义或优化相关功能。...

    SpringBoot 多模块 Serivce 层单元测试

    6. **断言(Assertion)**:测试完成后,我们需要使用JUnit的assert方法(如assertEquals()、assertTrue()等)来验证Service层方法的执行结果是否符合预期。 7. **测试覆盖率**:为了确保测试的全面性,我们还需要...

    yeoman-assert:yeoman的断言实用程序

    断言 yeoman-assert正在扩展本机Node.js assert模块。 yeoman-assert assert还可以使用assert每个方法,以及一些与代码框架相关的断言帮助器。安装 $ npm install yeoman-assert用法 const assert = require ( '...

    教育科研-学习工具-Linux平台下CLI模块的代码自动化测试方法.zip

    在Linux平台上进行CLI(命令行接口)模块的代码自动化测试是一项关键的技术实践,它能够显著提高软件开发的效率和质量。下面将详细讲解这个主题,包括相关知识点、测试原理以及实施步骤。 首先,理解CLI模块的基本...

    Python ddt模块数据驱动下载.rar

    在给定的"Python ddt模块数据驱动下载.rar"压缩包中,很可能包含了ddt库的源码、示例代码、可能的文档以及相关教程。 ddt的核心功能是将一个测试用例转化为多个独立的测试,每个用例对应一组不同的输入数据。这样,...

    node.js中的console.assert方法使用说明

    通过源码我们可以看到,console.assert方法内部实际上是对Node.js的assert模块的ok函数进行了调用。在断言失败的情况下,console.assert使用util.format方法来格式化错误信息,并将这个信息作为参数传递给assert.ok...

    C++模块间参数传递

    本文将介绍一种基于C++模板技术的模块间参数传递方式,旨在提高代码的灵活性和复用性。 #### 二、问题背景 当我们在设计软件时,经常遇到需要在不同模块之间传递各种类型的参数的情况。这些参数可能包括基本数据...

    nose代码检查工具

    nose可以通过第三方插件如`dupfind`或`radon`来检测代码中的重复部分,鼓励编写模块化、可重用的代码,提高代码质量。 ### 3. 使用nose进行测试驱动开发(TDD) nose支持测试驱动开发模式,鼓励开发者先编写测试...

Global site tag (gtag.js) - Google Analytics