使用Jasmine测试JavaScript(一)——基本概念

2023 review: 本文只是介绍了工具,并没有触及理论,有模块测试的理论——模块的设计,开发,测试和文档。

本文略译自《Testing JavaScript Using the Jasmine Framework

在过去,JavaScript代码是出了名很难测试的;幸好,得益于互联网和移动互联网的发展,JS测试工具 伴随JS开发生态圈的发展,被陆续开发出来。当前流行的JS测试工具/框架,包括 Jasmine,qUnit,YUI Test等。

其实大多数JS应用框架都配备了自己的测试工具/框架。框架相关的测试工具,和通用的测试工具(例如 Jasmine )都有自己的特点和适用性。另一个 选择测试框架的指标,就是测试工具是否依赖浏览器,如果不依赖浏览器,那么测试工具易用性会更高。

Jasmine三个基本概念

不管你过去是否有使用测试工具的经验,上手Jasmine使用不需要太多时间,了解几基本概念就可以了。

Jasmine 第一个重要概念是Suite

Suite——【测试套装】表征一组相关的【测验】(test case);

套装(Suite)由一集(一个以上)具体【测验】组成——将测验的结果(叫actual)与预期的值(expected value)进行比对。测验任务在jasmine称为 Expectations。

在技术上,套装(Suite)由全局API describe()定义:两个参数,一个BDD注1的Suite名,一个称为 Specs 实现方法,一个套装由多个规格测试组成。

Jasmine 第二个重要概念是Specs

在【套装】和【测验】之间还有一层组织,它就是软件规格(Specs)。软件规格就像套装概念一样,是逻辑的;

在技术上,规格(Specs)由全局API it()定义:两个参数,一个BDD的 Specs 名,一个 expectation 的实现方法。

it() function内可按需要使用变量(为什么要变量,这根据测验任务需要),并且有一个以上具体测验语句(Expectations)。

Jasmine 第三个重要概念是 Expectations

【完整的测验语句】由测验目标( expect() method)和断言组成,断言Jasmine称为匹配函数(Matcher),有断言才能产生一个真值,表明测验是否通过。以下是一个简单的例子:

describe("Stock Portfolio App Tests", function() {
  it("calcSideFundInterest() should return a value that is greater than the supplied fund value.", function() {
    var calcSideFundInterest = function(fundValue, dailyInt, period) {
      return fundValue * (dailyInt * period);
    };
    var fundValue = 1000, 
        dailyInt  = 0.00356, 
        period    = 7;
    var result = calcSideFundInterest(fundValue, dailyInt, period);
    expect(result).toBeGreaterThan(fundValue);
  });
});

综上所述, 逻辑上,每个Suite(describe)有一个以上的Spec(it),而一个Spec又有一个以上的test case(expect.matcher)

预定义 Matchers

在上面的例子里,toBeGreaterThan()就是匹配函数,或者 断言操作。Jasmine预定义了很多断言操作给我们使用,包括以下:

  • toBe: represents the exact equality (===) operator.
  • toEqual: represents the regular equality (==) operator.
  • toMatch: calls the RegExp match() method behind the scenes to compare string data.
  • toBeDefined: opposite of the JS "undefined" constant.
  • toBeUndefined: tests the actual against "undefined".
  • toBeNull: tests the actual against a null value - useful for certain functions that may return null, like those of regular expressions (same as toBe(null))
  • toBeTruthy: simulates JavaScript boolean casting.
  • toBeFalsy: like toBeTruthy, but tests against anything that evaluates to false, such as empty strings, zero, undefined, etc…
  • toContain: performs a search on an array for the actual value.
  • oBeLessThan/toBeGreaterThan: for numerical comparisons.
  • toBeCloseTo: for floating point comparisons.
  • toThrow: for catching expected exceptions.

此外,还有一个取反的断言操作not,例如 expect(false).not.toBe(true)。

Jasmine 支持自定义断言操作,本文不介绍自定义方法,只是提示。

规格测试对象实例的事件勾子

Jasmine为【规格测验】设计了生命勾子,每一次的规格测验的【前置条件】和【事后清理】分别在beforeEach()afterEach()里处理。可见规格测验才是测验对象实例。

describe("Stock Portfolio App Tests", function() {
  var presentValue, 
      previousValue, 
      aPercentChanges;

  beforeEach(function() {
    presentValue    = 110; 
    previousValue   = 100; 
    aPercentChanges = [];
  });

  afterEach(function() {
    presentValue    = 0;
    previousValue   = 0; 
    aPercentChanges = [];
  });

  it("calcWeeklyPercentChange() should return the change between two numbers as a percentage.", function() {
    var calcWeeklyPercentChange = function(presentValue, previousValue, aPercentChanges) {
      var percentChange = presentValue / previousValue - 1;
      aPercentChanges.push(percentChange);
      return percentChange;
    };

    //actually returns 0.10000000000000009!
    var result = calcWeeklyPercentChange(presentValue, previousValue, aPercentChanges);
    expect(result).toBeCloseTo(0.1);
    expect(aPercentChanges.length).toEqual(1);
  });

  it("The aPercentChanges array should now be empty.", function() {
    expect(aPercentChanges.length).toEqual(0);
  });
});

小结

到此,你学会了使用Jasmine的基本功能了。下一次,我们将讲如何在浏览器上进行测试,并且如何使用spy。

参考

https://jasmine.github.io/api/edge/matchers.html


  1. BDD扩展于TDD,使用不同方式编写测试用例,这些测试用任何人(不一定是程序员)都可以阅读和理解的自然语言来测试软件行为(需求)。单元测试的名称通常以单词“should”开头,并且按照业务价值的顺序编写。
裸男
Nakeman.cn 2023 Build by Gatsby and Tailwind, Deploy on Netlify.