文档章节

jasmine 行为驱动,测试先行

lightyarn
 lightyarn
发布于 2014/12/28 01:12
字数 1966
阅读 31
收藏 0

1. jasmine介绍

Jasmine是一个用来编写Javascript测试的框架,它不依赖于任何其它的javascript框架,也不需要对DOM。它有拥有灵巧而明确的语法可以让你轻松的编写测试代码。

jasmine的结构很简单:

describe("A suite", function() {
  var foo;
  beforeEach(function() {
    foo = 0;
    foo += 1;
  });

  afterEach(function() {
    foo = 0;
  });

  it("contains spec with an expectation", function() {
    expect(true).toBe(true);
  });
});

每个测试都在一个测试集中运行,Suite就是一个测试集,用describe函数封装。 Spec表示每个测试用例,用it函数封装。通过expect函数,作为程序断言来判断相等关系。setup过程用beforeEach函数封装,tearDown过程用afterEach封装。

用过Java中JUnit的同学,看到这种对应关系,应该就会明白jasmine就是JUnit的Javascript重写版。

2. jasmine安装

安装jasmine类库时,让我们利用bower,一键搞定。bower的使用介绍,请参考文章:bower解决js的依赖管理。把已经学到的知识用起来,效率马上提升10倍。

~ D:\workspace\javascript>mkdir jasmine
~ D:\workspace\javascript>cd jasmine

#查找jasmine项目
~ D:\workspace\javascript\jasmine>bower search jasmine
-----------------------------------------
Update available: 1.2.4 (current: 1.1.2)
Run npm update -g bower to update
-----------------------------------------

Search results:

    jasmine git://github.com/pivotal/jasmine.git
    jasmine-jquery git://github.com/velesin/jasmine-jquery
    jasmine-sinon git://github.com/froots/jasmine-sinon.git
    jasmine-ajax git://github.com/pivotal/jasmine-ajax.git
    jasmine.async git://github.com/derickbailey/jasmine.async.git
    flight-jasmine git://github.com/twitter/flight-jasmine.git
    jasmine-jstd-adapter git://github.com/ibolmo/jasmine-jstd-adapter.git
    jasmine-flight git://github.com/flightjs/jasmine-flight.git
    jasmine-signals git://github.com/AdamNowotny/jasmine-signals.git
    jasmine-underscore git://github.com/adscott/jasmine-underscore.git
    jasmine-bootstrap git://github.com/esbie/jasmine-bootstrap.git
    jasmine-data-provider git://github.com/sublimino/jasmine-data-provider.git
    jasmine-sugar git://github.com/fantactuka/jasmine-sugar.git

#安装jasmine类库
~ D:\workspace\javascript\jasmine>bower install jasmine
bower jasmine#*             not-cached git://github.com/pivotal/jasmine.git#*
bower jasmine#*                resolve git://github.com/pivotal/jasmine.git#*
bower jasmine#*               download https://github.com/pivotal/jasmine/archive/v1.3.1.tar.gz
bower jasmine#*                extract archive.tar.gz
bower jasmine#*               resolved git://github.com/pivotal/jasmine.git#1.3.1
bower jasmine#~1.3.1           install jasmine#1.3.1

jasmine#1.3.1 bower_components\jasmine

3. jasmine环境配置

jasmine运行需要4个部分:

  • 1. 运行时环境:我们这里基于chrome浏览器,通过HTML作为javascript载体

  • 2. 源文件:用于实现某种业务逻辑的文件,就是我们平时写的js脚本

  • 3. 测试文件:符合jasmineAPI的测试js脚本

  • 4. 输出结果:jasmine提供了基于网页的输出结果

下面让我开始jasmine:

1). 新建一个HTML文件:test.html

~ vi test.html

<!DOCTYPE html>
<html>
<head>
<title>jasmine test</title>
<link rel="stylesheet" type="text/css" href="bower_components/jasmine/lib/jasmine-core/jasmine.css">
<script type="text/javascript" src="bower_components/jasmine/lib/jasmine-core/jasmine.js"></script>
<script type="text/javascript" src="bower_components/jasmine/lib/jasmine-core/jasmine-html.js"></script>
</head>
<body>
<h1>jasmine test</h1>
<script type="text/javascript" src="src.js"></script>
<script type="text/javascript" src="test.js"></script>
<script type="text/javascript" src="report.js"></script>
</body>
</html>

我们看到页面上面有5个javascript的导入:

  • jasmine.js:核心文件用于执行单元测试的类库

  • jasmine-html.js:用于显示单元测试的结果的类库

  • src.js:我们自己的业务逻辑的js

  • test.js:单元测试的js

  • report.js:用于启动单元测试js

jasmine.js,jasmine-html.js是系统类库,直接引入。
report.js,是启动脚本,写法是固定的。

~ vi report.js

(function() {
  /**
   * ## Require &amp; Instantiate
   *
   * Require Jasmine's core files. Specifically, this requires and attaches all of Jasmine's code to the `jasmine` reference.
   */
  window.jasmine = jasmineRequire.core(jasmineRequire);
  /**
   * Since this is being run in a browser and the results should populate to an HTML page, require the HTML-specific Jasmine code, injecting the same reference.
   */
  jasmineRequire.html(jasmine);
  /**
   * Create the Jasmine environment. This is used to run all specs in a project.
   */
  var env = jasmine.getEnv();
  /**
   * ## The Global Interface
   *
   * Build up the functions that will be exposed as the Jasmine public interface. A project can customize, rename or alias any of these functions as desired, provided the implementation remains unchanged.
   */
  var jasmineInterface = jasmineRequire.interface(jasmine, env);
  /**
   * Add all of the Jasmine global/public interface to the proper global, so a project can use the public interface directly. For example, calling `describe` in specs instead of `jasmine.getEnv().describe`.
   */
  if (typeof window == "undefined" && typeof exports == "object") {
    extend(exports, jasmineInterface);
  } else {
    extend(window, jasmineInterface);
  }
  /**
   * ## Runner Parameters
   *
   * More browser specific code - wrap the query string in an object and to allow for getting/setting parameters from the runner user interface.
   */
  var queryString = new jasmine.QueryString({
    getWindowLocation: function() { return window.location; }
  });
  var catchingExceptions = queryString.getParam("catch");
  env.catchExceptions(typeof catchingExceptions === "undefined" ? true : catchingExceptions);
  /**
   * ## Reporters
   * The `HtmlReporter` builds all of the HTML UI for the runner page. This reporter paints the dots, stars, and x's for specs, as well as all spec names and all failures (if any).
   */
  var htmlReporter = new jasmine.HtmlReporter({
    env: env,
    onRaiseExceptionsClick: function() { queryString.setParam("catch", !env.catchingExceptions()); },
    getContainer: function() { return document.body; },
    createElement: function() { return document.createElement.apply(document, arguments); },
    createTextNode: function() { return document.createTextNode.apply(document, arguments); },
    timer: new jasmine.Timer()
  });
  /**
   * The `jsApiReporter` also receives spec results, and is used by any environment that needs to extract the results  from JavaScript.
   */
  env.addReporter(jasmineInterface.jsApiReporter);
  env.addReporter(htmlReporter);
  /**
   * Filter which specs will be run by matching the start of the full name against the `spec` query param.
   */
  var specFilter = new jasmine.HtmlSpecFilter({
    filterString: function() { return queryString.getParam("spec"); }
  });
  env.specFilter = function(spec) {
    return specFilter.matches(spec.getFullName());
  };
  /**
   * Setting up timing functions to be able to be overridden. Certain browsers (Safari, IE 8, phantomjs) require this hack.
   */
  window.setTimeout = window.setTimeout;
  window.setInterval = window.setInterval;
  window.clearTimeout = window.clearTimeout;
  window.clearInterval = window.clearInterval;
  /**
   * ## Execution
   *
   * Replace the browser window's `onload`, ensure it's called, and then run all of the loaded specs. This includes initializing the `HtmlReporter` instance and then executing the loaded Jasmine environment. All of this will happen after all of the specs are loaded.
   */
  var currentWindowOnload = window.onload;
  window.onload = function() {
    if (currentWindowOnload) {
      currentWindowOnload();
    }
    htmlReporter.initialize();
    env.execute();
  };
  /**
   * Helper function for readability above.
   */
  function extend(destination, source) {
    for (var property in source) destination[property] = source[property];
    return destination;
  }
}());

src.js是实现业务逻辑的文件,我们定义sayHello的函数

~ vi src.js

function sayHello(name){
    return "Hello " + name;
}

test.js对源文件进行单元测试

~ vi test.js

describe("A suite of basic functions", function() {
    var name;

    it("sayHello", function() {
        name = "Conan";
        var exp = "Hello Conan";
        expect(exp).toEqual(sayHello(name));
    });
});

页面报告截图:
test1

我们完成了,最基础的jasmine功能。

4. jasmine使用

1). 测试先行
测试先行,就是未写现实,先写用例。

我们刚才已经配置好了jasmine的环境,后面我们所有功能代码都写在src.js中,测试代码都写在test.js中。

有一个需求,要实现单词倒写的功能。如:”ABCD” ==> “DCBA”

我们编辑test.js,增加一个测试用例

~ vi test.js

it("reverse word",function(){
    expect("DCBA").toEqual(reverse("ABCD"));
});

执行这个页面,单元测试失败,提示没有reverse函数。
test2

编辑src.js,增加reverse函数

function reverse(name){
    return "DCBA";
}

执行页面,单元测试成功!
test3

单元测试成功,是不是能说明我们完成了“单词倒写”的功能呢?答案是不确定的。如果想保证功能是正确性,我们需要进行更多次的验证。

编辑test.js,继续增加测试用例

    it("reverse word",function(){
        expect("DCBA").toEqual(reverse("ABCD"));
        expect("Conan").toEqual(reverse("nanoC"));
    });

刷新页面,又提示单元测试失败,因为我们希望输入是”Conan”,输出是”nanoC”,但是功能代码返回是”DCBA”,显然业务逻辑写的是不对的。

修改src.js,修改reverse函数

~ vi src.js

function reverse(name){
    return name.split("").reverse().join("");
}

再次刷新页面,单元测试成功!! 

这是敏捷开发中提倡的“测试先行”的案例,对于产品级的代码,我们真的应该要高质量控制。

2). jasmine语法实践
以下内容是对jasmine语法的介绍,都在test.js中实现。

做一个嵌套的describe(“A suite of jasmine’s function”)

对断言表达式的使用

describe("A suite of jasmine's function", function() {
    describe("Expectations",function(){
        it("Expectations",function(){
            expect("AAA").toEqual("AAA");
            expect(52.78).toMatch(/\d*.\d\d/);
            expect(null).toBeNull();
            expect("ABCD").toContain("B");
            expect(52,78).toBeLessThan(99);
            expect(52.78).toBeGreaterThan(18);

            var x = true;
            var y;
            expect(x).toBe(true);
            expect(x).toBeDefined();
            expect(y).toBeUndefined();
            expect(x).toBeTruthy();
            expect(!x).toBeFalsy();

            var fun = function() { return a + 1;};
            expect(fun).toThrow();
        });
    });
});

对开始前和使用后的变量赋值

    describe("Setup and Teardown",function(){
        var foo;
        beforeEach(function() {
            foo = 0;
            foo += 1;
        });
        afterEach(function() {
            foo = 0;
        });

        it("is just a function, so it can contain any code", function() {
            expect(foo).toEqual(1);
        });

        it("can have more than one expectation", function() {
            expect(foo).toEqual(1);
            expect(true).toEqual(true);
        });
    });

对忽略suite的声明

   xdescribe("Disabling Specs and Suites", function() {
        it("Disabling Specs and Suites",function(){
            expect("AAA").toEqual("AAA");
        });
    });

对异步程序的单元测试

   describe("Asynchronous Support",function(){
        var value, flag;
        it("Asynchronous Support", function() {
            runs(function() {
                flag = false;
                value = 0;
                setTimeout(function() {
                    flag = true;
                }, 500);
            });
            waitsFor(function() {
                value++;
                return flag;
            }, "The Value should be incremented", 750);

            runs(function() {
                expect(value).toBeGreaterThan(0);
            });
        });
    });

我们成功地对Javascript完成各种的单元测试,下面是测试报告。
test4


本文转载自:http://blog.fens.me/nodejs-jasmine-bdd

上一篇: brew on mac
lightyarn
粉丝 1
博文 18
码字总数 8711
作品 0
南昌
私信 提问
Karma和Jasmine自动化单元测试

转自http://blog.fens.me/nodejs-karma-jasmine/ 前言 在Java领域,Apache, Spring, JBoss 三大社区的开源库,包罗万象,但每个库都在其领域中都鹤立鸡群。而Nodejs中各种各样的开源库,却让...

山里来的鱼
2015/08/05
1K
2
javascript 自动化单元测试

#JavaScript 自动化单元测试 - 为什么要进行自动化测试? - 什么项目适合做自动化测试? - 测试运行器 karma - 测试框架 jasmine ### 为什么要进行自动化测试? 1. 正确性:验证代码的正确性...

945996501
2018/06/26
0
0
自动化测试框架--Jasmine-iphone

Jasmine-iphone 是 iPhone UI 自动化测试框架,能够使用 Jasmine 驱动 iPhone UI 自动化测试。

大胖森
2015/05/15
1K
0
使用 Karma + Jasmine 构建 Web 测试环境

使用 Karma + Jasmine 构建 Web 测试环境 刘 刚 2017 年 11 月 07 日发布 简介 现在,越来越多的 Web 框架涌现了出来,令人眼花缭乱。随着浏览器的不断演化,一些前端框架开始尝试将服务器端...

刘 刚
2017/11/07
0
0
搭建和学习Angularjs官方示例angular-phonecat项目

一、简介 最近需要学习angularjs,可是官方的网站在中国不是很友好,访问不是很方便。 还好找到了下面的一个更齐全点的官方示例angular-phonecat项目的教程网站PhoneCat 入门教程 App 导言 ...

dhb_oschina
2016/04/22
2.3K
0

没有更多内容

加载失败,请刷新页面

加载更多

前端技术之:Prisma Demo服务部署过程记录

安装前提条件: 1、已经安装了docker运行环境 2、以下命令执行记录发生在MackBook环境 3、已经安装了PostgreSQL(我使用的是11版本) 4、Node开发运行环境可以正常工作 首先需要通过Node包管...

popgis
今天
5
0
数组和链表

数组 链表 技巧一:掌握链表,想轻松写出正确的链表代码,需要理解指针获引用的含义: 对指针的理解,记住下面的这句话就可以了: 将某个变量赋值给指针,实际上就是将这个变量的地址赋值给指...

code-ortaerc
今天
4
0
栈-链式(c/c++实现)

上次说“栈是在线性表演变而来的,线性表很自由,想往哪里插数据就往哪里插数据,想删哪数据就删哪数据...。但给线性表一些限制呢,就没那么自由了,把线性表的三边封起来就变成了栈,栈只能...

白客C
今天
43
0
Mybatis Plus service

/** * @author beth * @data 2019-10-20 23:34 */@RunWith(SpringRunner.class)@SpringBootTestpublic class ServiceTest { @Autowired private IUserInfoService iUserInfoS......

一个yuanbeth
今天
5
0
php7-internal 7 zval的操作

## 7.7 zval的操作 扩展中经常会用到各种类型的zval,PHP提供了很多宏用于不同类型zval的操作,尽管我们也可以自己操作zval,但这并不是一个好习惯,因为zval有很多其它用途的标识,如果自己...

冻结not
昨天
6
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部