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