Jasmine中文指南

jasmine是一款非常流行的测试框架,不依赖任何别的库,语法简单,本文是2.1版本的api中文指南.

运行条件

  • npm install -g jasmine
  • jasmine JASMINE_CONFIG_PATH=jasmine.json
  • jasmine.json配置文件可以随意命名,内容格式如下

    {
      "spec_dir": "jasminetest",
      "spec_files": [
        "*.js"
      ]
    }
  • spec_dir代表要测试用例的目录,spec_files代表要测试的文件信息

一个简单的jasmine测试用例总是以describe开始的,它代表一组相似的测试用例,然后具体的测试用例以it开始,先看看下面简单的例子

describe(' test some code ', function(){
    var foo = 'foo';

    it(' expect foo equal foo ', function(){
        expect(foo).toEqual('foo');
    });

})

下面是jasmine的常用断言方法,在任何断言方法前面加上not,代表相反的意思.

toBe

类似于`===`
expect(true).toBe(true);

toEqual

比较变量字面量的值
expect({ foo: 'foo'}).toEqual( {foo: 'foo'} );

toMatch

匹配值与正则表达式
expect('foo').toMatch(/foo/);

toBeDefined

检验变量是否定义
var foo = {
    bar: 'foo'
};
expect(foo.bar).toBeDefined();

toBeNull

检验变量是否为`null`
var foo = null;
expect(foo).toBeNull();

toBeTruthy

检查变量值是否能转换成布尔型`真`值
expect({}).toBeTruthy();

toBeFalsy

检查变量值是否能转换成布尔型`假`值
expect('').toBeFalsy();

toContain

检查在数组中是否包含某个元素
expect([1,2,4]).toContain(1);

toBeLessThan

检查变量是否小于某个数字
expect(2).toBeLessThan(10);

toBeGreaterThan

检查变量是否大于某个数字或者变量
expect(2).toBeGreaterThan(1);

toBeCloseTo

比较两个数在保留几位小数位之后,是否相等,用于数字的精确比较
expect(3.1).toBeCloseTo(3, 0);

toThrow

检查一个函数是否会throw异常
expect(function(){ return a + 1;}).toThrow();  // true
expect(function(){ return a + 1;}).not.toThrow(); // false

toHaveBeenCalled

检查一个监听函数是否被调用过
  • 代码见下面的监听函数部分

toHaveBeenCalledWith

检查监听函数调用时的参数匹配信息
  • 代码见下面的监听函数部分

测试前后注入

  • beforeEach

    在describe里的每个it执行前调用

describe('test code inject', function(){
    var foo;

    // 每次给foo加1
    beforeEach(function(){
        foo += 1;
    });

    it('expect foo toBe 1 ', function(){
        expect(foo).toBe(1);
    });

    it('expect foo toEqual 2 ', function(){
        expect(foo).toEqual(2);
    });

});
  • afterEach

    在describe里的每个it执行后调用

describe('test code inject', function(){
    var foo;

    // 每次给foo加1
    beforeEach(function(){
        foo += 1;
    });

    // 重置变量foo
    afterEach(function(){
        foo = 0;
    });

    it('expect foo toBe 1 ', function(){
        expect(foo).toBe(1);
    });

    it('expect foo toEqual 1 ', function(){
        expect(foo).toEqual(1);
    });

});
  • beforeAll

    保证在describe里所有的it执行之前调用

describe('test beforeAll ', function(){
    var foo;

    // 只执行一次,保证在it执行之前执行
    beforeAll(function(){
        foo += 1;
    });

    it('expect foo toBe 1 ', function(){
        expect(foo).toBe(1);
    });

    it('expect foo toEqual 1 ', function(){
        expect(foo).toEqual(1);
    });

});
  • afterAll

    保证在describe里所有的it执行完成之后调用

describe('test beforeAll ', function(){
    var foo;

    // 只执行一次,保证在it执行之前执行
    beforeAll(function(){
        foo += 1;
    });

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

    it('expect foo toBe 1 ', function(){
        expect(foo).toBe(1);
        foo += 1;
    });

    it('expect foo toEqual 2 ', function(){
        expect(foo).toEqual(2);
    });

    // foo 0

});

this关键字

  • describe里的每个beforeEach,it,afterEachthis都是相同的.

describe('test this context', function(){

    beforeEach(function(){
        this.bar = 'yicai';
    });

    afterEach(function(){
        console.log(this.bar); // yicai
    });

    it('expect this.bar yicai ', function(){
        console.log(this.bar); // yicai
    });

    it('expect this.bar yicai ', function(){
        console.log(this.bar); // yicai
    });

});

嵌套describe

  • 不同层次的it执行时,会按从外到内依次执行beforeEach,每个it执行结束时,会按从内到外依次执行afterEach.

describe('test nesting describe ', function(){

    var foo = 0;

    beforeEach(function(){
        foo += 1;
    });
    afterEach(function(){
        foo = 0;
        console.log('second invoke parent afterEach');
    })

    it('expect foo toBe 1', function(){
        expect(foo).toBe(1);
    });

    describe('child describe ', function(){
        beforeEach(function(){
            foo += 1;
        })
        afterEach(function(){
            console.log('first invoke child afterEach');
        })

        it('expect foo toEqual 2', function(){
            expect(foo).toEqual(2);
        });
    })
});

禁用describe与it

  • 当在describeit前面加上x前缀时,可以禁掉当前describe和it测试
  • 当使用xit或者it里不包含函数体时,测试结果会显示挂起spec字样

spy监视函数执行

  • spyOn方法可以添加对某个对象下的函数执行情况的监控

describe('test spy ', function(){
    var  spyobj, bar = null;
    beforeEach(function(){
        spyobj = {
            setBar: function(val){
                bar = val;
            }
        }
        spyOn(spyobj, 'setBar');
        spyobj.setBar('123');
        spyobj.setBar('1', '2');
    });

    it('check spyobj invoke track', function(){
        // 检查是否监听函数是否调用过
        expect(spyobj.setBar).toHaveBeenCalled();
        // 检查监听函数参数调用情况
        expect(spyobj.setBar).toHaveBeenCalledWith('123');
        expect(spyobj.setBar).toHaveBeenCalledWith('1', '2');
        // bar变量值默认是不会保存的
        expect(bar).toBeNull();
    })
});
  • and.callThrough方法可以让监听的方法返回值保留下来

describe('test spy ', function(){
    var  spyobj, bar = null;
    beforeEach(function(){
        spyobj = {
            setBar: function(val){
                bar = val;
            }
        }
        spyOn(spyobj, 'setBar').and.callThrough();
        spyobj.setBar('123');
        spyobj.setBar('1', '2');
    });

    it('check spyobj invoke track', function(){
        // bar变量此次保存了下来
        expect(bar).toEqual('1');
    })
});
  • and.returnValue方法可以指定监听的方法返回值

describe('test spy ', function(){
    var  spyobj, bar = null, foo;
    beforeEach(function(){
        spyobj = {
            setBar: function(val){
                bar = val;
            },
            getBar: function(){
                return bar;
            }
        }
        spyOn(spyobj, "getBar").and.returnValue('1');
        spyobj.setBar('123');
        foo = spyobj.getBar();
    });

    it('check spyobj invoke track', function(){

        expect(bar).toEqual('123');
        // returnValue改变了原先的setBar方法设置的值
        expect(foo).toEqual('1');
    })
});
  • and.callFake方法可以伪造监听的方法返回值,通过一个自定义函数

describe('test spy ', function(){
    var  spyobj, bar = null, foo;
    beforeEach(function(){
        spyobj = {
            setBar: function(val){
                bar = val;
            },
            getBar: function(){
                return bar;
            }
        }
        spyOn(spyobj, "getBar").and.callFake(function(){
            return 'yicai';
        });
        spyobj.setBar('123');
        foo = spyobj.getBar();
    });

    it('check spyobj invoke track', function(){

        expect(bar).toEqual('123');
        // callFake改变了原先的setBar方法设置的值
        expect(foo).toEqual('yicai');
    })
});
  • and.throwError方法可以让监听方法执行之后返回一个错误信息,可以通过toThrowError来适配

describe('test spy ', function(){
    var  spyobj, bar = null;
    beforeEach(function(){
        spyobj = {
            setBar: function(val){
                bar = val;
            },
            getBar: function(){
                return bar;
            }
        }
        spyOn(spyobj, "setBar").and.throwError('error');
    });

    it('check spyobj invoke track', function(){
        expect(function(){
            spyobj.setBar();
        }).toThrowError('error');
    })
});
  • and.stub方法可以还原监听方法的返回值

describe('test spy ', function(){
    var  spyobj, bar = null;
    beforeEach(function(){
        spyobj = {
            setBar: function(val){
                bar = val;
            },
            getBar: function(){
                return bar;
            }
        }
        spyOn(spyobj, "setBar").and.callThrough();
    });

    it('check spyobj invoke track', function(){
        spyobj.setBar('123');
        expect(bar).toEqual('123');
        spyobj.setBar.and.stub();
        bar = null;
        spyobj.setBar('123');
        expect(bar).toBe(null);
    })
});
  • calls这里包含很多监听过程中的属性信息

    • .calls.any(),一次都没调用,则返回false,否则返回true
    • .calls.count(),返回监听函数调用的次数
    • .calls.argsFor(index),返回监听函数调用过程中传递的所有参数信息,index代表调用的索引数
    • .calls.allArgs(),返回监听函数调用过程中的所以参数信息,是一个数组,每一项代表一次调用传参信息
    • .calls.all(),返回监听函数调用过程中的所有信息,除了参数信息还包含this上下文信息
    • .calls.mostRecent(),返回监听函数最后一次调用的相关信息,除了参数还包含this上下文信息
    • .calls.first(),返回第一次调用监听函数的相关信息,除了参数还包含this上下文信息
    • .calls.reset(),清除监听函数调用信息,.calls.any()将返回false

下面以一个例子来说明,在访问监听函数上的calls属性时的信息

describe('test spy ', function(){
    var  spyobj, bar = null;
    beforeEach(function(){
        spyobj = {
            setBar: function(val){
                bar = val;
            },
            getBar: function(){
                return bar;
            }
        }
        spyOn(spyobj, "setBar");
    });

    it('check spyobj invoke track', function(){

        // 监听函数没调用过,则返回false
        expect(spyobj.setBar.calls.any()).toBe(false);

        spyobj.setBar('1');
        spyobj.setBar('2', '4');
        // 上面调用了2次
        expect(spyobj.setBar.calls.count()).toEqual(2);

        // 分别获取上面调用两次时的入参信息,索引就是调用顺序
        expect(spyobj.setBar.calls.argsFor(0)).toEqual(['1']);
        expect(spyobj.setBar.calls.argsFor(1)).toEqual(['2', '4']);

        // 获取所有调用时的入参信息
        expect(spyobj.setBar.calls.allArgs()).toEqual([ ['1'], ['2', '4'] ]);

        // 获取所有调用信息,包括this上下文信息
        expect(spyobj.setBar.calls.all()).toEqual([
        {
            object: spyobj, args: ['1'], returnValue: undefined
        },
        {
            object: spyobj, args: ['2','4'], returnValue: undefined
        }
        ]);

        // 获取最近一次调用的信息
        expect(spyobj.setBar.calls.mostRecent()).toEqual({object: spyobj, args: ['2', '4'], returnValue: undefined});

        // 获取第一次调用的信息
        expect(spyobj.setBar.calls.first()).toEqual({object: spyobj, args: ['1'], returnValue: undefined});

        // 清除监听函数调用信息
        spyobj.setBar.calls.reset();

        expect(spyobj.setBar.calls.any()).toBe(false);
    })
});

注意,当在calls对象上调用all(),mostRecent(),first(),返回的object属性指向的是this上下文信息

  • createSpy,可以创建一个命名的监听函数

describe('test spy ', function(){
    var  spyobj, bar = null;
    beforeEach(function(){
        spyobj = jasmine.createSpy('spyobj');
        spyobj('1', '2');
    });

    it('check spyobj invoke track', function(){

        expect(spyobj.and.identity()).toEqual('spyobj');

        expect(spyobj.calls.any()).toBe(true);

        expect(spyobj.calls.count()).toEqual(1);

        expect(spyobj).toHaveBeenCalledWith('1', '2');

        expect(spyobj.calls.mostRecent().args[0]).toEqual('1');
    })
});
  • createSpyObj,可以批量创建监听函数

describe('test spy ', function(){
    var  spyobj, bar = null;
    beforeEach(function(){
        spyobj = jasmine.createSpyObj('spyobj', ['play', 'pause', 'stop', 'rewind']);
        spyobj.play();
        spyobj.pause('1');
    });

    it('check spyobj invoke track', function(){

        expect(spyobj.rewind.and.identity()).toEqual('spyobj.rewind');

        expect(spyobj.play.calls.any()).toBe(true);

        expect(spyobj.stop.calls.any()).toBe(false);

        expect(spyobj.pause.calls.count()).toEqual(1);

        expect(spyobj.pause.calls.mostRecent().args[0]).toEqual('1');
    })
});

jasmine.any

检验变量是否匹配相关类型
describe("jasmine.any", function() {
  it("matches any value", function() {
    expect({}).toEqual(jasmine.any(Object));
    expect(12).toEqual(jasmine.any(Number));
  });

  describe("when used with a spy", function() {
    it("is useful for comparing arguments", function() {
      var foo = jasmine.createSpy('foo');
      foo(12, function() {
        return true;
      });

      expect(foo).toHaveBeenCalledWith(jasmine.any(Number), jasmine.any(Function));
    });
  });
});

jasmine.objectContaining

检验对象是否包含某个`key/value`
describe("jasmine.objectContaining", function() {
  var foo;

  beforeEach(function() {
    foo = {
      a: 1,
      b: 2,
      bar: "baz"
    };
  });

  it("matches objects with the expect key/value pairs", function() {
    expect(foo).toEqual(jasmine.objectContaining({
      bar: "baz"
    }));
    expect(foo).not.toEqual(jasmine.objectContaining({
      c: 37
    }));
  });

  describe("when used with a spy", function() {
    it("is useful for comparing arguments", function() {
      var callback = jasmine.createSpy('callback');

      callback({
        bar: "baz"
      });

      expect(callback).toHaveBeenCalledWith(jasmine.objectContaining({
        bar: "baz"
      }));
      expect(callback).not.toHaveBeenCalledWith(jasmine.objectContaining({
        c: 37
      }));
    });
  });
});

jasmine.clock

jasmine的时钟
  • jasmine.clock().install(), 启动时钟控制
  • jasmine.clock().uninstall(), 停止时钟控制
  • jasmine.clock().tick, 让时钟往前走多少秒
  • jasmine.clock().mockDate, 可以根据传入的date来设置当前时间

下面以一个完整的例子来说明

describe('test jasmine.clock', function(){
    var timecallback;

    beforeEach(function(){
        timecallback = jasmine.createSpy('timecallback');
        jasmine.clock().install();
    });

    afterEach(function(){
        jasmine.clock().uninstall();
    })

    it('mock setTimeout clock ', function(){
        setTimeout(function(){
            timecallback();
        }, 100);
        expect(timecallback).not.toHaveBeenCalled();
        jasmine.clock().tick(101);
        expect(timecallback).toHaveBeenCalled();
    })

    it('mock setInterval clock ', function(){
        setInterval(function(){
            timecallback();
        }, 100);
        expect(timecallback).not.toHaveBeenCalled();
        jasmine.clock().tick(101);
        expect(timecallback.calls.count()).toEqual(1);
        jasmine.clock().tick(50);
        expect(timecallback.calls.count()).toEqual(1);
        jasmine.clock().tick(50);
        expect(timecallback.calls.count()).toEqual(2);
    })

    it('mock date clock ', function(){
        var baseTime = new Date(2013, 9, 23);
        jasmine.clock().mockDate(baseTime);
        jasmine.clock().tick(50);
        expect(new Date().getTime()).toEqual(baseTime.getTime() + 50);
    })

})

jasmine异步支持

  • beforeEachit,包装的函数传入done参数,只有当done函数执行完成之后,beforeEach, it才算执行完成
  • jasmine.DEFAULT_TIMEOUT_INTERVAL, 默认是5秒之后就超时,可以修改这个超时时间

下面以一个完整的例子来说jasmine中异步操作

describe('test asynchonous ', function(){
    var value = 0, originalTimeout;

    beforeEach(function(done){
        originalTimeout = jasmine.DEFAULT_TIMEOUT_INTERVAL;
        // 设置jasmine超时时间为10秒
        jasmine.DEFAULT_TIMEOUT_INTERVAL = 10000;
        setTimeout(function(){
            value += 1;
            // 只有执行done函数,后面的it才会执行
            done();
        }, 200);
    });

    afterEach(function(){
        // 还原jasmine超时时间
        jasmine.DEFAULT_TIMEOUT_INTERVAL = originalTimeout;
    })

    it('expect value toEqual 1', function(done){
        setTimeout(function(){
            expect(value).toEqual(1);
            // 只有执行这个,后面的it才会执行
            done();
        }, 9000);
    });

    it('until above spec complete ', function(){
        expect(value).toBe(2);
    });

})

相关链接

Jasmine 2.1 英文api文档

时间: 2024-12-21 17:10:31

Jasmine中文指南的相关文章

Day01 - JavaScript Drum Kit 中文指南

Day01 - JavaScript Drum Kit 中文指南 作者:liyuechun简介:JavaScript30 是 Wes Bos 推出的一个 30 天挑战.项目免费提供了 30 个视频教程.30 个挑战的起始文档和 30 个挑战解决方案源代码.目的是帮助人们用纯 JavaScript 来写东西,不借助框架和库,也不使用编译器和引用.现在你看到的是这系列指南的第 1 篇.完整指南在 从零到壹全栈部落. 简介 第一天的练习是用JS制作一个爵士鼓的页面,通过敲击键盘上不同的字母,会发出不同

Day05 - Flex 实现可伸缩的图片墙 中文指南

Day05 - Flex 实现可伸缩的图片墙 中文指南 作者:liyuechun简介:JavaScript30 是 Wes Bos 推出的一个 30 天挑战.项目免费提供了 30 个视频教程.30 个挑战的起始文档和 30 个挑战解决方案源代码.目的是帮助人们用纯 JavaScript 来写东西,不借助框架和库,也不使用编译器和引用.现在你看到的是这系列指南的第 5 篇.完整指南在 从零到壹全栈部落. 实现效果 点击任意一张图片,图片展开,同时从图片上下两方分别移入文字.点击已经展开的图片后,图

Day07 - Array Cardio 中文指南二

Day07 - Array Cardio 中文指南二 作者:liyuechun简介:JavaScript30 是 Wes Bos 推出的一个 30 天挑战.项目免费提供了 30 个视频教程.30 个挑战的起始文档和 30 个挑战解决方案源代码.目的是帮助人们用纯 JavaScript 来写东西,不借助框架和库,也不使用编译器和引用.现在你看到的是这系列指南的第 7 篇.完整中文版指南及视频教程在 从零到壹全栈部落. 第七天的练习是接着之前Day04 - Array Cardio 中文指南一的练习

开源图书 —— 《Docker中文指南》

Docker中文指南 详细介绍docker正式版已经推出,做的改动非常多,以前版本的docker翻译已经不能用了,所以现在重新开始希望有兴趣的朋友一起加入! About the author Questions and Issues Edit and Contribute Introduction 安装篇 1.1. Mac OS X 1.2. Ubuntu 1.3. Red Hat Enterprise Linux 1.4. CentOS 1.5. Debain 1.6. Gentoo 1.7.

Mocha中文指南

mocha是一款比较流行的测试框架,出自TJ之手,跟jasmine相比,它有灵活的断言语法,测试提示也比较友好,其它方面跟jasmine类似. 使用条件 npm install -g mocha mocha *.js mocha跟jasmine一个显著区别在于,它的断言库不是固定的,支持nodejs自带的assert库,should.js,expect.js,chai,better-assert,然后也支持BDD语法的describe与it. 因为should.js也是TJ写的,所以这里重点介绍

英国主机商Host1Plus推出中文站进军中国市场

中介交易 http://www.aliyun.com/zixun/aggregation/6858.html">SEO诊断 淘宝客 云主机 技术大厅 近日,英国主机商Host1Plus于日前正式推出中文官方网站http://cn.Host1Plus.com,Host1Plus中文站的推出也是其进军中国市场的一个强有力的信号,这也是继五月份Webhostingpad推出中文网站http://cn.webhostingpad.com之后,又一家入驻中国虚拟主机市场的国外主机商. Host1p

看懂前端脚手架你需要这篇WEBPACK

本文转载自网络.转载编辑过程中,可能有遗漏或错误,请以原文为准. 原文作者:二口南洋 原文链接: https://gold.xitu.io/post/586ddb8ab123db005d0b65cb Webpack 是当下最热门的前端资源模块化管理和打包工具.它可以将许多松散的模块按照依赖和规则打包成符合生产环境部署的前端资源.还可以将按需加载的模块进行代码分隔,等到实际需要的时候再异步加载.通过loader 的转换,任何形式的资源都可以视作模块,比如 CommonJs 模块. AMD 模块.

Python资源大全

The Python Tutorial (Python 2.7.11) 的中文翻译版本.Python Tutorial 为初学 Python 必备官方教程,本教程适用于 Python 2.7.X 系列. 在线阅读 » Fork Me » The Python Tutorial (Python 3.5.1) 的中文翻译版本.Python Tutorial 为初学 Python 必备官方教程,本教程适用于 Python 3.5.x. 在线阅读 » Fork Me » Flask 是一个轻量级的 We

前端知识库

前端开发全面知识库,包括HTML5,CSS3和js的基本框架知识,以及DOM和BOM操作的基础知识和一些基本工具和IDE.学习本篇,你将了解到以下知识. 核心 Core HTML5 W3C http://www.w3school.com.cn/html5/ W3C https://www.w3.org/html/ig/zh/wiki/HTML5 菜鸟教程 http://www.runoob.com/html/html5-intro.html HTML5中文门户 http://www.html5c