Jasmine 是流行的 JavaScript 单元测试框架之一,能够测试同步和异步 JavaScript 代码。
它用于 BDD(行为驱动开发)编程,它更关注业务价值而不是技术细节。
Jasmine匹配器
在第一个例子中,我们看到了 toEqual
和 toThrow
函数的用法。
它们是匹配器,用于比较任何 jasmine 测试的实际和预期输出。
如果它可以帮助你,你就像java断言一样。
让我们列出所有此类 Jasmine 匹配器,它们可以实现更强大和更有意义的测试规范。
Matcher | 目的 |
---|---|
toBe() | 如果实际值与预期值的类型和值相同,则通过。它与 === 运算符比较 |
toEqual() | 适用于简单的文字和变量; 也适用于对象 |
toMatch() | 检查值是否与字符串或者正则表达式匹配 |
toBeDefined() | 确保定义了属性或者值 |
toBeUndefined() | 确保属性或者值未定义 |
toBeNull() | 确保属性或者值为空。 |
toBeTruthy() | 确保属性或者值是“true” |
ToBeFalsy() | 确保属性或者值是“false” |
toContain() | 检查字符串或者数组是否包含子字符串或者项目。 |
toBeLessThan() | 对于小于的数学比较 |
toBeGreaterThan() | 对于大于的数学比较 |
toBeCloseTo() | 用于精确的数学比较 |
toThrow() | 用于测试函数是否抛出异常 |
toThrowError() | 用于测试特定抛出的异常 |
Jasmine not
关键字可以与每个匹配器的条件一起使用,以反转结果。
例如
expect(actual).not.toBe(expected); expect(actual).not.toBeDefined(expected);
设置和拆卸
为了设置和拆除,Jasmine 在套件级别提供了两个全局函数,例如:beforeEach()
和 afterEach()
。
beforeEach()
beforeEach
函数在调用它的 describe()
中的每个规范之前被调用一次。
afterEach()
afterEach
函数在每个规范之后被调用一次。
在实践中,规范变量(是任何)在顶级范围定义 - describe
块 - 并且初始化代码被移动到 beforeEach
函数中。afterEach
函数在继续之前重置变量。
这有助于开发人员不要为每个规范重复设置和完成代码。
Jasmine 设置配置
首先下载 jasmine 框架并将其解压缩到项目文件夹中。
我建议在/js
或者/javascript
文件夹下创建一个单独的文件夹/jasmine
,该文件夹可能已经存在于应用程序中。
我们将在分发包中获得以下四个文件夹/文件:
/src
: 包含要测试的 JavaScript 源文件/lib
: 包含框架文件/spec
: 包含 JavaScript 测试文件SpecRunner.html
: 是测试用例运行器 HTML 文件
你可以删除/src
文件夹;并从“SpecRunner.html”文件中的当前位置引用源文件。
默认文件如下所示,我们需要更改包含在 /src
和 /spec
文件夹中的文件。
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>Jasmine Spec Runner v2.4.1</title> <link rel="shortcut icon" type="image/png" href="lib/jasmine-2.4.1/jasmine_favicon.png"> <link rel="stylesheet" href="lib/jasmine-2.4.1/jasmine.css"> <script src="lib/jasmine-2.4.1/jasmine.js"></script> <script src="lib/jasmine-2.4.1/jasmine-html.js"></script> <script src="lib/jasmine-2.4.1/boot.js"></script> <!-- include source files here... --> <script src="src/Player.js"></script> <script src="src/Song.js"></script> <!-- include spec files here... --> <script src="spec/SpecHelper.js"></script> <script src="spec/PlayerSpec.js"></script> </head> <body></body> </html>
为了专注于 Jasmine 的能力,我们创建一个简单的 JS 文件“MathUtils.js”,其中包含一些基本操作,我们将对这些功能进行单元测试。
MathUtils = function() {}; MathUtils.prototype.sum = function(number1, number2) { return number1 + number2; } MathUtils.prototype.substract = function(number1, number2) { return number1 - number2; } MathUtils.prototype.multiply = function(number1, number2) { return number1 * number2; } MathUtils.prototype.divide = function(number1, number2) { return number1 / number2; } MathUtils.prototype.average = function(number1, number2) { return (number1 + number2) / 2; } MathUtils.prototype.factorial = function(number) { if (number < 0) { throw new Error("There is no factorial for negative numbers"); } else if (number == 1 || number == 0) { return 1; } else { return number * this.factorial(number - 1); } }
在SpecRunner.html
中添加文件引用后,文件内容将是:
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>Jasmine Spec Runner v2.4.1</title> <link rel="shortcut icon" type="image/png" href="lib/jasmine-2.4.1/jasmine_favicon.png"> <link rel="stylesheet" href="lib/jasmine-2.4.1/jasmine.css"> <script src="lib/jasmine-2.4.1/jasmine.js"></script> <script src="lib/jasmine-2.4.1/jasmine-html.js"></script> <script src="lib/jasmine-2.4.1/boot.js"></script> <!-- include source files here... --> <script src="../MathUtils.js"></script> <!-- include spec files here... --> <script src="spec/MathUtils.js"></script> </head> <body></body> </html>
Jasmine描述块
在 Jasmine 中,describe
函数用于对相关规范进行分组。
字符串参数用于命名规范的集合,并将与规范连接以形成规范的全名。
这有助于在大型套件中查找规格。
好消息是,我们也可以嵌套 describe
块。
在嵌套 describe
的情况下,在执行规范之前,Jasmine 按顺序向下执行每个 beforeEach
函数,然后执行规范,最后向上执行每个 afterEach
函数。
替换MathUtilSpecs.js
中代码:
describe("Nested Describe Demo", function() { beforeEach(function() { console.log("beforeEach level 1"); }); describe("MyTest level2", function() { beforeEach(function() { console.log("beforeEach level 2"); }); describe("MyTest level3", function() { beforeEach(function() { console.log("beforeEach level 3"); }); it("is a simple spec in level3", function() { console.log("A simple spec in level 3"); expect(true).toBe(true); }); afterEach(function() { console.log("afterEach level 3"); }); }); afterEach(function() { console.log("afterEach level 2"); }); }); afterEach(function() { console.log("afterEach level 1"); }); });
现在通过在浏览器中打开“SpecRunner.html”来执行这个文件。
观察控制台输出,它写成:
beforeEach level 1 beforeEach level 2 beforeEach level 3 A simple spec in level 3 afterEach level 3 afterEach level 2 afterEach level 1
Jasmine suite 和 spec
在 Jasmine 中,有两个重要的术语 suite 和 spec 。
suite
Jasmine 套件是一组测试用例,可用于测试 JavaScript 代码(JavaScript 对象或者函数)的特定行为。
这从调用 Jasmine 全局函数 describe
开始,其中有两个参数,第一个参数表示测试套件的标题,第二个参数表示实现测试套件的函数。
//This is test suite describe("Test Suite", function() { //..... });
Spec
Jasmine 规范(Spec)代表测试套件中的一个测试用例。
这从调用 Jasmine 全局函数 it
开始,它有两个参数,第一个参数表示规范的标题,第二个参数表示实现测试用例的函数。
实际上,规范包含一个或者多个期望。
每个期望代表一个断言,可以是 true
或者 false
。
为了通过规范,规范中的所有期望都必须为“true”。
如果规范中的一个或者多个期望为“false”,则规范失败。
//This is test suite describe("Test Suite", function() { it("test spec", function() { expect( expression ).toEqual(true); }); });
让我们开始为MathUtils.js
编写单元测试以更好地理解套件和规范。
我们将在 spec/MathUtils.js
中编写这些规范。
describe("MathUtils", function() { var calc; //This will be called before running each spec beforeEach(function() { calc = new MathUtils(); }); describe("when calc is used to peform basic math operations", function(){ //Spec for sum operation it("should be able to calculate sum of 3 and 5", function() { expect(calc.sum(3,5)).toEqual(8); }); //Spec for multiply operation it("should be able to multiply 10 and 40", function() { expect(calc.multiply(10, 40)).toEqual(400); }); //Spec for factorial operation for positive number it("should be able to calculate factorial of 9", function() { expect(calc.factorial(9)).toEqual(362880); }); //Spec for factorial operation for negative number it("should be able to throw error in factorial operation when the number is negative", function() { expect(function() { calc.factorial(-7) }).toThrowError(Error); }); }); });
在浏览器中打开 SpecRunner.html
文件时,运行规范并在浏览器中呈现结果。
禁用Suite 和Spec
很多时候,出于各种原因,我们可能希望禁用Suite一段时间。
在这种情况下,我们不需要删除代码,而只需在 describe
的开头添加字符 x
即可生成 if xdescribe
。
这些套件和其中的任何规格在运行时都会被跳过,因此它们的结果不会出现在结果中。
xdescribe("MathUtils", function() { //code });
如果我们不想禁用整个套件,而只想禁用某个规范测试,则将 x
放在该规范本身之前,这次只会跳过该规范。
describe("MathUtils", function() { //Spec for sum operation xit("should be able to calculate the sum of two numbers", function() { expect(10).toBeSumOf(7, 3); }); });