您的位置:首页 > 其它

Jasmine Introduction —— Jasmine 测试框架初探

2016-03-18 16:58 417 查看
Jasmine 的介绍在网上随处可见,在此我们先摘录官网对其的描述:
Jasmine is a behavior-driven development framework for testing JavaScript code. It does not depend on any other JavaScript frameworks. It does not require a DOM. And it has a clean, obvious syntax so that you can easily write tests.
Jasmine 是一款 BDD(Behaviour-drive development) 的JavaScript 测试框架。它独立于其他的 JS 框架自成一体,且并不需要 DOM 作为支撑。语法简单,书写容易也是其优势之一。

Jasmine 的实用性、易用性已经在大量的实际使用的中得到了验证,所以本文不再赘述。这里我们将重点放在:怎样从零开始使用 Jasmine 测试我们现存的 JavaScript 代码。

在浏览器中运行 Jasmine 测试框架:
首先,我们可以在 https://github.com/jasmine/jasmine/releases 下载到最新发布的 Jasmine standalone distribution。
以我下载的 Jasmine-standalone-2.4.1 为例,解压后文件目录结构如下,可以看到里面已经有一些示例代码:



其中 /lib 文件夹下包含了测试框架的源码等文件。
/src 下包含了待测试的 JS 代码。里面包含两个文件 Song.js 和 Player.js
/spec 下则包含了对应的测试代码,PlayerSpec.js 和 SpecHelper.js

直接在浏览器中打开 SpecRunner.html,就可以看到如下页面,



表示 SpecRunner.html 中包含的 5 个测试用例都顺利通过了。

本文中,我们不再对这部分代码进行研究,而是直接创建我们自己的测试用例。在 /src 下添加 Hello.js

var Hello = function() {};

Hello.prototype.foo = "foo";
Hello.prototype.bar = null    ;

Hello.prototype.helloWorld = function() {
return "Hello World!";
}

Hello.prototype.helloSomeone = function(toGreet) {
return this.sayHello() + " " + toGreet;
}

Hello.prototype.sayHello = function() {
return "Hello";
}


在 /spec 下添加 Hello.matcher.js

beforeEach(function () {
jasmine.addMatchers({
toContainWord: function () {
return {
compare: function (actual, expected) {
var result = {};
result.pass = (actual.indexOf(expected) !== -1);
if( result.pass ) {
result.message = "Expected " + actual + " to contain " + expected + ".";
} else {
result.message = "Expected " + actual + " to contain " + expected + ", but it does not.";
}
return result;
}
}
}
});
});


然后写下我们自己的测试 Hello.spec.js:

describe("Hello", function () {
var hello;

beforeEach(function () {
hello = new Hello();
});

it("a newly created Hello instance should not be the same instance with the origin one", function () {
expect(hello).not.toBe(new Hello());
expect(hello).toEqual(new Hello());
});

describe("helloWorld function", function () {
it("should return hello statement", function () {
expect(hello.helloWorld()).toBe("Hello World!");
});

it("should contain word 'World'", function () {
expect(hello.helloWorld()).toContainWord("World!");
});

it("an undefined variable should pass 'toBeUndefined' matcher", function () {
expect(hello.a).toBeUndefined();
});

it("a null variable should pass 'toBeNull' matcher", function () {
expect(hello.bar).toBeNull();
});

it("variable after boolean casting should pass 'toBeTruthy' 'toBeFalsy' matcher", function () {
expect(hello.foo).toBeTruthy();
expect(hello.bar).toBeFalsy();
});
it("should pass the 'toMatch' matcher for regular expressions", function (){
expect(hello.helloWorld()).toMatch(/^\w*\s\w*!$/);
});
});

describe("helloSomeone function", function () {
it("should calls the sayHello() function", function () {
spyOn(hello, "sayHello");
hello.helloSomeone("Chou");
expect(hello.sayHello).toHaveBeenCalled();
expect(hello.sayHello).toHaveBeenCalledTimes(1);
});
it("should greet the 'World'", function () {
spyOn(hello, "helloSomeone");
hello.helloSomeone("World");
expect(hello.helloSomeone).toHaveBeenCalledWith("World");
expect(hello.helloSomeone).not.toHaveBeenCalledWith("world");
});
it("should calls the fake sayHello()", function () {
hello.sayHello = jasmine.createSpy("'sayHello' spy");
hello.helloSomeone("world");
expect(hello.sayHello).toHaveBeenCalled();
});
});
});


第一步是 describe 我们的测试。一个测试是由 Jasmin 中的 describe function 开始的。describe 需要两个参数, 一个 String 和一个 function。在这个 String 中我们可以描述测试的名字和意图,通常是对被测试对象的描述。funciton 中则包含我们具体的测试代码。
It function, 也就是 ‘Spec’,也和describe 一样,含有两个参数,一个String和一个function。String具体描述这个测试单元的目的,在本例中,我们使用 Should do sth. when sth. happened 的格式,以使测试单元看起来更整洁也更便于理解。
一个 spec 中会包含一或多个 expectation。 Jasmine 中的 expectation 就像 JUnit 中的 assertion 一样,会对判断条件进行判断并返回 true/fase,只有当一个 spec 中所有的 expectation 全部通过时,我们才可以称之为一个 passing spec。
然后是 Matchers。每一个matcher都会比较实际输入的值,与期望的值,并返回一个 boolean。根据matchers 返回的Boolean值,jasmine决定是否让一个spec顺利通过。每一个matcher都可以通过在前面插入一个 not 声明,来实现一个相反的assertion。
在本例中,我们使用了几种常见的 Matcher: toBe toEqual toMatch toBeDefined toBeTruthy toBeNull toContain。也使用了一个自定义的 Matcher ‘toContainWord’。这个 Matcher 检查我们待判断 String 是否包含传入的参数。如
expect(“Hello World!”).toContainWord(“World!”)
就能够顺利通过 Matcher 的判断。

同其他测试框架一样,为了减少代码重复,jasmine也提供了一些全局方法来进行 setup/teardown
分别为 beforeEach, afterEach, beforeAll, afterAll。
其中 beforeAll 会在所有 spec 运行前执行一次,afterAll 则会在所有 spec 运行完成后执行一次。在 beforeAll 和afterAll中我们可以做一些成本比较高的操作,以提高我们的测试效率。不过这样做同时也会提高风险,不同 spec 之间可能会互相影响而导致测试失败。所以使用时需要多加小心。
不同于 beforeAll 和 afterAll, beforeEach 和 afterEach 则会在每个 spec 前后分别执行。
所以这些方法执行流程大体如下:

beforeAll
beforeEach
spec

afterEach
beforeEach
spec

afterEach

afterAll

做完以上工作,我们就成功的建立了自己的第一个 Jasmine 测试了

接下来就是修改 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="src/Hello.js"></script>

<!-- include spec files here... -->
<script src="spec/Hello.matcher.js"></script>
<script src="spec/Hello.spec.js"></script>

</head>

<body>
</body>
</html>


在 SpecRunner.html 中,务必要先引入所有 jasmine 的依赖文件:
jasmine.css
jasmine.js
jasmine-html.js
boot.js
再引入我们待测试的 Hello.js,最后则是我们的测试文件 Hello.matcher.js 和 Hello.spec.js。

做好以上的步骤,我们再打开 SpecRunner.html:



就能看到我们新增的 10 个测试全部通过啦。

希望本文能对广大第一次接触 Jasmine 的朋友们有所帮助,有何问题也请多多指教。

如果你希望获取更多更详细的介绍,请参考官方文档:http://jasmine.github.io/2.4/introduction.html
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: