测试驱动javascript开发 -- 2.单元测试一例:学习断言、测试用例函数的编写

简介:   本篇我们将通过对Date.strftime编写单元测试的例子,学会断言、测试用例函数的相关知识。   首先我们先来看Date.strftime的实现代码。 Date.prototype.strftime = (function () {   function strftime(form...

  本篇我们将通过对Date.strftime编写单元测试的例子,学会断言、测试用例函数的相关知识。

  首先我们先来看Date.strftime的实现代码。

Date.prototype.strftime = (function () {
  function strftime(format) {
    var date = this;
    return (format + "").replace(/%([a-zA-Z])/g,
      function (m, f) {
        var formatter = Date.formats && Date.formats[f];
        if (typeof formatter == "function") {
          return formatter.call(Date.formats, date);
        } else if (typeof formatter == "string") {
          return date.strftime(formatter);
        }
        return f;
      });
  }
  // 内部帮助函数
  function zeroPad(num) {
    return (+num < 10 ? "0" : "") + num;
  }
  Date.formats = {
    // Formatting 方法
    d: function (date) {
      return zeroPad(date.getDate());
    },
    m: function (date) {
      return zeroPad(date.getMonth() + 1);
    },
    y: function (date) {
      return zeroPad(date.getYear() % 100);
    },
    Y: function (date) {
      return date.getFullYear();
    },
    // Format 速记方式
    F: "%Y-%m-%d",
    D: "%m/%d/%y"
  };
  return strftime;
}());

  Date.prototype.strftime函数整体是一个即时匿名函数,该函数会自动执行,把strftime函数作为结果返回。strftime()通过正则表的式判断格式化标示符,返回正确的结果。 zeroPad()在1-9的数据前加0 。Date.formats 对象提供一系列辅助方法,用来处理时间。

  如果代码有哪里看不懂可以给我留言,我会尽量讲解。

 

  断言

  单元测试的核心是断言,通过它的自动运行来比较开发者对于系统的预期结果是否和执行结果一致。两者一致则说明我们的系统一切正常,否则就存在问题,需要我们进一步确认。我们先来看一个简单的断言函数:

function assert(message, expr) {
  if (!expr) {
    throw new Error(message);
  }
  assert.count++;
  return true;
}
assert.count = 0;

  上面的函数只是简单的验证第二个参数是否是真值(除了false, null, undefined, 0, "", 和 NaN这些值之外的都可以)。断言成功,assert.count会加1,失败则抛出异常。

  我们可以使用他来测试strftime() 方法。

var date = new Date(2009, 9, 2);
try {
  assert("%Y should return full year", date.strftime("%Y") === "2009");
  assert("%m should return month", date.strftime("%m") === "10");
  assert("%d should return date", date.strftime("%d") === "02");
  assert("%y should return year as two digits", date.strftime("%y") === "09");
  assert("%F should act as %Y-%m-%d", date.strftime("%F") === "2009-10-02");
  console.log(assert.count + " tests OK");
} catch (e) {
  console.log("Test failed: " + e.message);
}

  在自动化测试中,我们经常使用绿色代表成功,红色代表失败。我们可以创建一个output方法输出不同颜色的信息条,代替console.log的功能。

function output(text, color) {
  var p = document.createElement("p");
  p.innerHTML = text;
  p.style.color = color;
  document.body.appendChild(p);
}
// 可以用它来代替上面断言例子中的 console.log
output(assert.count + " tests OK", "#0c0");
// 失败的时候使用下面的方法:
output("Test failed: " + e.message, "#c00");

 

  测试用例函数

  在创建断言函数之后,我们需要创建测试用例函数,以便把断言组织起来。测试用例里面包含很多子的测试方法,每个测试方法针对被测对象的一部分行为进行测试。下面我们看一个简单的测试用例函数的实现,其中name是测试用例的名称,tests是一组测试方法,其中每个测试方法以‘test’开头。

function testCase(name, tests) {
  assert.count = 0;
  var successful = 0;
  var testCount = 0;
  
for (var test in tests) {     if (!/^test/.test(test)) {       continue;     }
    testCount
++;
    
try {       tests[test]();       output(test, "#0c0");       successful++;     } catch (e) {       output(test + " failed: " + e.message, "#c00");     }   }
  
var color = successful == testCount ? "#0c0" : "#c00";   output("<strong>" + testCount + " tests, " + (testCount - successful) + " failures</strong>", color); }

  下面我们使用上面的方法测试strftime()。

var date = new Date(2009, 9, 2);
testCase("strftime test", {
  "test format specifier %Y": function () {
    assert("%Y should return full year", date.strftime("%Y") === "2009");
  },
  "test format specifier %m": function () {
    assert("%m should return month", date.strftime("%m") === "10");
  },
  "test format specifier %d": function () {
    assert("%d should return date", date.strftime("%d") === "02");
  },
  "test format specifier %y": function () {
    assert("%y should return year as two digits", date.strftime("%y") === "09");
  },
  "test format shorthand %F": function () {
    assert("%F should act as %Y-%m-%d", date.strftime("%F") === "2009-10-02");
  }
});

  这组测试方法针对strftime()不同功能点进行测试,组合起来实现了对其全部功能的测试,最后把测试结果展现给用户。可以说效果还是相当不错的。

  Setup 和 Teardown

  接下来我们介绍setup()和teardown()方法的实现。这两个方法分别在tests执行之前和之后运行,setup()可以用来初始化测试条件,teardown()可以用来销毁相关条件。下面我们完善之前的testCase()方法,添加对setup和teardown()的支持。

function testCase(name, tests) {
  assert.count = 0;
  var successful = 0;
  var testCount = 0;
  var hasSetup = typeof tests.setUp == "function";
  var hasTeardown = typeof tests.tearDown == "function";
  for (var test in tests) {
    if (!/^test/.test(test)) {
      continue;
    }
    testCount++;
    try {
      if (hasSetup) {
        tests.setUp();
      }
      tests[test]();
      output(test, "#0c0");
      if (hasTeardown) {
        tests.tearDown();
      }
      successful++;
    } catch (e) {
      output(test + " failed: " + e.message, "#c00");
    }
  }
  var color = successful == testCount ? "#0c0" : "#c00";
  output("<strong>" + testCount + " tests, " + (testCount - successful) + " failures</strong>", color);
}

  下面我们用改进后的testCase()重新测试strftime()方法。

testCase("strftime test", {
  setUp: function () {
    this.date = new Date(2009, 9, 2, 22, 14, 45);
  },
  "test format specifier Y": function () {
    assert("%Y should return full year", this.date.strftime("%Y") == 2009);
  },
  // ...
});

 

  总结

  本文提供的断言和测试用例函数比较简单,相信大家一看就会,其他复杂的测试框架则要相对复杂的多。但是他们在基本原理上没有太大差别,只是代码实现方式不同,再者就是api提供的更多些。本文主要目地在于抛砖引玉,向大家介绍测试框架中相关方法大致的实现方式,以及如何使用测试框架进行单元测试。要想更好的精通单元测试,除了继续加强理论知识的学习、不断的实践之外,还可以看看其他框架的源代码,相信对你定会有比较大的帮助。

目录
相关文章
|
人工智能 自然语言处理 测试技术
从人工到AI驱动:天猫测试全流程自动化变革实践
天猫技术质量团队探索AI在测试全流程的落地应用,覆盖需求解析、用例生成、数据构造、执行验证等核心环节。通过AI+自然语言驱动,实现测试自动化、可溯化与可管理化,在用例生成、数据构造和执行校验中显著提效,推动测试体系从人工迈向AI全流程自动化,提升效率40%以上,用例覆盖超70%,并构建行业级知识资产沉淀平台。
从人工到AI驱动:天猫测试全流程自动化变革实践
|
数据采集 人工智能 监控
人工智能驱动的软件工程:测试左移的崛起价值
本文探讨了人工智能驱动下测试左移理念在软件工程中的重要性,分析测试工程师在需求评估、AI代码生成及遗留系统优化中的关键作用,揭示AI带来的挑战与机遇,并指出测试工程师需提升技能、关注合规与可维护性,以在AI时代保障软件质量。
739 89
|
数据采集 算法 测试技术
【硬件测试】基于FPGA的1024QAM基带通信系统开发与硬件片内测试,包含信道模块,误码统计模块,可设置SNR
本文介绍了基于FPGA的1024QAM基带通信系统的硬件测试版本,包含testbench、高斯信道模块和误码率统计模块。系统新增ila在线数据采集和vio在线SNR设置模块,支持不同SNR条件下的性能测试。1024QAM调制将10比特映射到复平面上的1024个星座点之一,实现高效数据传输。硬件测试结果表明,在SNR=32dB和40dB时,系统表现出良好的性能。Verilog核心程序展示了各模块的连接与功能实现。
487 7
|
机器学习/深度学习 人工智能 并行计算
AI部署架构:A100、H100、A800、H800、H20的差异以及如何选型?开发、测试、生产环境如何进行AI大模型部署架构?
AI部署架构:A100、H100、A800、H800、H20的差异以及如何选型?开发、测试、生产环境如何进行AI大模型部署架构?
AI部署架构:A100、H100、A800、H800、H20的差异以及如何选型?开发、测试、生产环境如何进行AI大模型部署架构?
|
传感器 人工智能 JavaScript
鸿蒙开发:DevEcoTesting中的稳定性测试
DevEcoTesting主要的目的也是用于软件的测试,可以让开发者无需复杂的配置,即可一键执行测试任务,同时提供了测试报告和分析,无论是对于开发者还是测试同学来说,都是一个非常方便的工具。
476 3
鸿蒙开发:DevEcoTesting中的稳定性测试
|
存储 测试技术 API
数据驱动开发软件测试脚本
今天刚提交了我的新作《带着ChatGPT玩转软件开发》给出版社,在写作期间跟着ChatGPT学到许多新知识。下面分享数据驱动开发软件测试脚本。
499 0
|
人工智能 自然语言处理 JavaScript
测试工程师要失业?Magnitude:开源AI Agent驱动的端到端测试框架,让Web测试更智能,自动完善测试用例!
Magnitude是一个基于视觉AI代理的开源端到端测试框架,通过自然语言构建测试用例,结合推理代理和视觉代理实现智能化的Web应用测试,支持本地运行和CI/CD集成。
3018 15
测试工程师要失业?Magnitude:开源AI Agent驱动的端到端测试框架,让Web测试更智能,自动完善测试用例!
|
机器学习/深度学习 JavaScript 前端开发
JS进阶教程:递归函数原理与篇例解析
通过对这些代码示例的学习,我们已经了解了递归的原理以及递归在JS中的应用方法。递归虽然有着理论升华,但弄清它的核心思想并不难。举个随手可见的例子,火影鸣人做的影分身,你看到的都是同一个鸣人,但他们的行为却能在全局产生影响,这不就是递归吗?雾里看花,透过其间你或许已经深入了递归的魅力之中。
564 19
|
敏捷开发 运维 数据可视化
DevOps看板工具中的协作功能:如何打破开发、测试与运维之间的沟通壁垒
在DevOps实践中,看板工具通过可视化任务管理和自动化流程,提升开发与运维团队的协作效率。它支持敏捷开发、持续交付,助力团队高效应对需求变化,实现跨职能协作与流程优化。
|
运维 jenkins 测试技术
"还在苦等开发部署环境?3步教你用Jenkins拿回测试主动权"
测试工程师最头疼的问题是什么?依赖开发部署环境! 开发延期→测试时间被压缩→紧急上线后BUG频出→测试背锅。传统流程中,测试被动等待部署,效率低下。而Jenkins自动化部署让测试人员自主搭建环境,实现: ✅ 随时触发测试,不再苦等开发 ✅ 部署效率提升10倍,抢回测试时间 ✅ 改善团队协作,减少互相甩锅 学习Jenkins部署能力,成为高效测试工程师,告别被动等待!