广州海珠网站设计,北京市网站制作设计,买拆车件上什么网站,网站开发需要经过的几个主要阶段最近的项目在使用AngulaJs,对JS代码的测试问题就摆在了面前。通过对比我们选择了 Karma jasmine ,使用 Jasmine做单元测试 #xff0c;Karma 自动化完成#xff0c;当然了如果使用 Karma jasmine 前提是必须安装 Nodejs。
安装好 Nodejs #xff0c;使用 npm 安装好必要… 最近的项目在使用AngulaJs,对JS代码的测试问题就摆在了面前。通过对比我们选择了 Karma jasmine ,使用 Jasmine做单元测试 Karma 自动化完成当然了如果使用 Karma jasmine 前提是必须安装 Nodejs。
安装好 Nodejs 使用 npm 安装好必要的包写了一个测试用例测试通过很好很强大。 没有 Nodejs 环境可以使用 Jasmine 做单元测试吗当然可以我们可以到 官网下一个示例看一看比较简单。今天先讲一下如果直接使用
jasmine 做单元测试 简单示例 jasmine 示例下载地址 https://github.com/jasmine/jasmine/releases 选择最新版本下载下来示例代码结构如图 lib 文件夹下面 boot.js 启动文件 console.js 输出辅助文件 jasmine-html.js 测试页面 Dom 操作文件 jasmine.js jasmine核心文件 spec 文件夹 PlayerSpec.js 单元测试文件 SpecHelper.js jasmine 断言扩展文件自定义 Matcher src 文件夹 下面是被测试的 js 文件。 SpecRunner.html 为测试结果页面。 SpecRunner.html 代码注意js文件加载顺序 View Code 我们直接运行 SpecRunner.html 测试结果如下 5个 specs,0个失败全部通过。在 PlayerSpec.js 里添加一个Suite看看报错是什么样的。 1 2 3 4 5 describe(error test,function() { it(Here the test does not pass,function() { expect(1).toBe(2); }); }) 哈哈测试未通过看到没这里显示了详细的错误信息。 jasmine 语法详解 首先了解几个概念 Suite 指一个测试集 describe方法标志着一个测试集。 Spec 表示测试用例jasmine中用方法it来开始 specs。 一个 Suite可以包含多个 Spec一个 spec 可以包含多个 expections 断言 示例1 1 2 3 4 5 6 7 8 //测试集 开始于调用全局Jasmine函数describe有两个参数一个字符串和一个函数。 //该字符串是specs(测试用例)单元测试的名称或标题 - 通常是被测试的。 该函数是一个实现单元测试的代码块。 describe(A suite, function() { it(contains spec with an expectation, function() { expect(true).toBe(true); }); }); 示例2 包含多个断言 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 describe(A suite is just a function, function() { var a; it(and so is a spec, function() { a true; expect(a).toBe(true); }); }); describe(The toBe matcher compares with , function() { it(and has a positive case, function() { expect(true).toBe(true); }); it(and can have a negative case, function() { expect(false).not.toBe(true); }); }); 示例3 常用语法describe嵌套 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 describe(Included matchers:, function() { it(The toBe matcher compares with , function() { var a 12; var b a; expect(a).toBe(b); expect(a).not.toBe(null); }); describe(The toEqual matcher, function() { it(works for simple literals and variables, function() { var a 12; expect(a).toEqual(12); }); it(should work for objects, function() { var foo { a: 12, b: 34 }; var bar { a: 12, b: 34 }; expect(foo).toEqual(bar); }); }); it(The toMatch matcher is for regular expressions, function() { var message foo bar baz; expect(message).toMatch(/bar/); expect(message).toMatch(bar); expect(message).not.toMatch(/quux/); }); it(The toBeDefined matcher compares against undefined, function() { var a { foo: foo }; //已定义 expect(a.foo).toBeDefined(); expect(a.bar).not.toBeDefined(); }); it(The toBeUndefined matcher compares against undefined, function() { var a { foo: foo }; //未定义 expect(a.foo).not.toBeUndefined(); expect(a.bar).toBeUndefined(); }); it(The toBeNull matcher compares against null, function() { var a null; var foo foo; expect(null).toBeNull(); expect(a).toBeNull(); expect(foo).not.toBeNull(); }); it(The toBeTruthy matcher is for boolean casting testing, function() { var a, foo foo; expect(foo).toBeTruthy(); expect(a).not.toBeTruthy(); }); it(The toBeFalsy matcher is for boolean casting testing, function() { var a, foo foo; expect(a).toBeFalsy(); expect(foo).not.toBeFalsy(); }); describe(The toContain matcher, function() { it(works for finding an item in an Array, function() { var a [foo, bar, baz]; //包含 expect(a).toContain(bar); expect(a).not.toContain(quux); }); it(also works for finding a substring, function() { var a foo bar baz; expect(a).toContain(bar); expect(a).not.toContain(quux); }); }); it(The toBeLessThan matcher is for mathematical comparisons, function() { var pi 3.1415926, e 2.78; //小于 expect(e).toBeLessThan(pi); expect(pi).not.toBeLessThan(e); }); it(The toBeGreaterThan matcher is for mathematical comparisons, function() { var pi 3.1415926, e 2.78; //大于 expect(pi).toBeGreaterThan(e); expect(e).not.toBeGreaterThan(pi); }); it(The toBeCloseTo matcher is for precision math comparison, function() { var pi 3.1415926, e 2.78; //临近 是比较两个值是否足够接近不一定要相等 //源码pass: Math.abs(expected - actual) (Math.pow(10, -precision) / 2) //即 pi - e 的绝对值 是否 小于 10 的 X2 次方 / 2 //以 expect(pi).not.toBeCloseTo(e, 3); 为例就是 pi 跟 e 的差 绝对值 是否小于 1/1000 除以 2 ,即 0.0005 expect(pi).not.toBeCloseTo(e, 2); expect(pi).toBeCloseTo(e, 0); }); it(The toThrow matcher is for testing if a function throws an exception, function() { var foo function() { return 1 2; }; var bar function() { return a 1; }; //是否引发异常 expect(foo).not.toThrow(); expect(bar).toThrow(); }); it(The toThrowError matcher is for testing a specific thrown exception, function() { var foo function() { throw new TypeError(foo bar baz); }; //是否抛出指定错误 expect(foo).toThrowError(foo bar baz); expect(foo).toThrowError(/bar/); expect(foo).toThrowError(TypeError); expect(foo).toThrowError(TypeError, foo bar baz); }); }); //手动制造一个断言失败 //fail函数使specs(测试用例)失败。 它可以将失败消息或Error对象作为参数。 describe(A spec using the fail function, function() { var foo function(x, callBack) { if (x) { callBack(); } }; it(should not call the callBack, function() { foo(false, function() { fail(Callback has been called); }); }); }); //分组相关规则带 //describe 函数用于对相关specs(测试用例)进行分组。 string参数用于命名specs的集合并且将与specs连接以构成spec的全名。 //这有助于在 测试集 找到规则。 如果你很好地命名他们你的规则读为传统的BDD风格的完整句子。 describe(A spec, function() { it(is just a function, so it can contain any code, function() { var foo 0; foo 1; expect(foo).toEqual(1); }); it(can have more than one expectation, function() { var foo 0; foo 1; expect(foo).toEqual(1); expect(true).toEqual(true); }); }); 示例4 beforeEachafterEachbeforeAll和afterAll函数 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 //顾名思义beforeEach函数在调用它的describe中的每个 spec 之前调用一次afterEach函数在每个spec之后调用一次。 //这里是同一组specs(测试用例)写得有点不同。 被测变量定义在顶层作用域 - 描述块和初始化代码被移入一个beforeEach函数。 //afterEach函数在继续之前重置变量。 describe(A spec using beforeEach and afterEach, function() { var foo 0; beforeEach(function() { 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); }); }); //beforeAll函数仅在describe中的所有specs(测试用例)运行之前调用一次并且afterAll函数在所有specs(测试用例)完成后调用。 //这些功能可用于加快测试集 的昂贵设置和拆卸。 //但是要小心使用beforeAll和afterAll 由于它们不在specs(测试用例)之间重置很容易在specs(测试用例)之间意外泄漏状态 //使它们错误地通过或失败。 注意跟 beforeEach 的区别 //如果 在第1个 it 里改变了 foo 的值第2个 it 的值就不是 初始化时的值了 describe(A spec using beforeAll and afterAll, function() { var foo; beforeAll(function() { foo 1; }); afterAll(function() { foo 0; }); it(sets the initial value of foo before specs run, function() { expect(foo).toEqual(1); foo 1; }); it(does not reset foo between specs, function() { expect(foo).toEqual(2); }); }); 示例5 this关键字共享变量嵌套describe 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 //this关键字 //另一种在beforeEachit和afterEach之间共享变量的方法是通过this关键字。 //每个spec的beforeEach / it / afterEach都将这个作为同一个空对象对于下一个spec的beforeEach / it / afterEach设置为空。 describe(A spec, function() { beforeEach(function() { this.foo 0; }); it(can use the this to share state, function() { expect(this.foo).toEqual(0); this.bar test pollution?; }); it(prevents test pollution by having an empty this created for the next spec, function() { expect(this.foo).toEqual(0); //注意这里的区别 undefined expect(this.bar).toBe(undefined); }); }); //嵌套describe describe 里嵌套 describe //调用describe可以嵌套在任何级别定义specs(测试用例)。 这允许一个单元测试被组成一个函数树。 //在执行specs(测试用例)之前Jasmine沿着树顺序执行每个beforeEach函数。 //在specs(测试用例)执行后Jasmine类似地遍历 afterEach 函数。 describe(A spec, 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); }); describe(nested inside a second describe, function() { var bar; beforeEach(function() { bar 1; }); it(can reference both scopes as needed, function() { expect(foo).toEqual(bar); }); }); }); 示例6 Pending 待定规则 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 //待定规则 //待处理的规则不会运行但它们的名称将在结果中显示为待处理。 describe(Pending specs, function() { //任何用xit声明的spec都被标记为pending。 xit(can be declared xit, function() { expect(true).toBe(false); }); //在没有函数体的情况下声明的任何specs(测试用例)也将在结果中被标记为待处理 it(can be declared with it but without a function); //pending() 如果你在specs(测试用例)体中任何地方调用该函数无论预期如何specs(测试用例)将被标记为待定。 //pending()函数接受一个字符串参数该参数会在结果集中显示在 PENDING WITH MESSAGE:之后作为为何被Pending的原因。 it(can be declared by calling pending in the spec body, function() { expect(true).toBe(false); pending(this is why it is pending); }); }); 示例7 Spies 对象监控 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 // Spies //Jasmine有 spies(监控) 双重测试功能。 spy 可以存根任何函数并跟踪对它和所有参数的调用。 //spy 只存在于描述或其定义的块中并且将在每个specs(测试用例)之后删除。 有特殊的匹配器与 spies 交互。 //Jasmine 2.0的语法已更改。 describe(A spy, function() { var foo, bar null; beforeEach(function() { foo { setBar: function(value) { bar value; } }; spyOn(foo, setBar); //spyOn(foo, setBar).and.callThrough(); foo.setBar(123); foo.setBar(456, another param); }); //如果调用 Spies toHaveBeenCalled匹配器将返回true。 //是否被调用 it(tracks that the spy was called, function() { expect(foo.setBar).toHaveBeenCalled(); }); //如果 Spies 被调用了指定的次数toHaveBeenCalledTimes匹配器将通过。 it(tracks that the spy was called x times, function() { expect(foo.setBar).toHaveBeenCalledTimes(2); }); //如果参数列表匹配任何记录的调用到 Spies toHaveBeenCalledWith匹配器将返回true。 it(tracks all the arguments of its calls, function() { expect(foo.setBar).toHaveBeenCalledWith(123); expect(foo.setBar).toHaveBeenCalledWith(456, another param); }); it(stops all execution on a function, function() { //有没有感到奇怪beforeEach 里调用了 foo.setBar()这里为什么 bar 的值为 null ?? //原因是 spyOn(foo, setBar); 并不会去调用 真实的 foo.setBar()函数只是调用了 Jasmine 保存的这个函数的 存根不会影响到实际的值 //如果这样写 spyOn(foo, setBar).and.callThrough(); 就会调用真实的 foo.setBar()函数了bar的值也会跟随改变 expect(bar).toBeNull(); }); }); // Spies and.callThrough //通过使用and.callThrough链接 Spies Spies 仍然会跟踪对它的所有调用但此外它将委派给实际的实现。 describe(A spy, when configured to call through, function() { var foo, bar, fetchedBar; beforeEach(function() { foo { setBar: function(value) { bar value; }, getBar: function() { return bar; } }; spyOn(foo, getBar).and.callThrough(); foo.setBar(123); fetchedBar foo.getBar(); }); it(tracks that the spy was called, function() { expect(foo.getBar).toHaveBeenCalled(); }); it(should not affect other functions, function() { expect(bar).toEqual(123); }); it(when called returns the requested value, function() { //这里 fetchedBar 有值 //这就是 spyOn(foo, getBar).and.callThrough() 跟 spyOn(foo, getBar) 的区别 expect(fetchedBar).toEqual(123); }); }); // Spies and.returnValue //通过使用and.returnValue链接 Spies 所有对函数的调用都将返回特定的值。 describe(A spy, when configured to fake a return value, function() { var foo, bar, fetchedBar; beforeEach(function() { foo { setBar: function(value) { bar value; }, getBar: function() { return bar; } }; spyOn(foo, getBar).and.returnValue(745); foo.setBar(123); //所有调用 foo.getBar() 函数都返回 745 fetchedBar foo.getBar(); }); it(tracks that the spy was called, function() { expect(foo.getBar).toHaveBeenCalled(); }); it(should not affect other functions, function() { expect(bar).toEqual(123); }); it(when called returns the requested value, function() { expect(fetchedBar).toEqual(745); }); }); // specs and.returnValues //通过使用and.returnValues链接 specs 所有对函数的调用将按顺序返回特定的值 //直到它到达返回值列表的结尾此时它将返回未定义的所有后续调用。 describe(A spy, when configured to fake a series of return values, function() { var foo, bar; beforeEach(function() { foo { setBar: function(value) { bar value; }, getBar: function() { return bar; } }; spyOn(foo, getBar).and.returnValues(fetched first, fetched second); foo.setBar(123); }); it(tracks that the spy was called, function() { //返回调用次数 对应的 参数数组 下标的值 foo.getBar(123); expect(foo.getBar).toHaveBeenCalled(); }); it(should not affect other functions, function() { //不要迷惑了赋值是在 beforeEach 里做的不是 foo.getBar(123); expect(bar).toEqual(123); }); it(when called multiple times returns the requested values in order, function() { //返回调用次数 对应的 参数数组 下标的值 expect(foo.getBar()).toEqual(fetched first); expect(foo.getBar()).toEqual(fetched second); expect(foo.getBar()).toBeUndefined(); }); }); // specs and.callFake //通过使用and.callFake链接 specs 所有对 specs 的调用都将委派给提供的函数。 describe(A spy, when configured with an alternate implementation, function() { var foo, bar, fetchedBar; beforeEach(function() { foo { setBar: function(value) { bar value; }, getBar: function() { return bar; } }; //如果被窥探的函数接收到假的需要的参数你可以得到那些 spyOn(foo, getBar).and.callFake(function(arguments, can, be, received) { return 1001; }); foo.setBar(123); fetchedBar foo.getBar(); }); it(tracks that the spy was called, function() { expect(foo.getBar).toHaveBeenCalled(); }); it(should not affect other functions, function() { expect(bar).toEqual(123); }); it(when called returns the requested value, function() { expect(fetchedBar).toEqual(1001); }); }); // specs and.throwError //通过使用and.throwError链接 specs 所有对 specs 的调用都将抛出指定的值作为错误。 describe(A spy, when configured to throw an error, function() { var foo, bar; beforeEach(function() { foo { setBar: function(value) { bar value; } }; spyOn(foo, setBar).and.throwError(quux); }); it(throws the value, function() { expect(function() { foo.setBar(123) }).toThrowError(quux); }); }); // specs and.stub //当调用策略用于 specs 时可以随时使用and.stub返回原始的存根行为。 describe(A spy, function() { var foo, bar null; beforeEach(function() { foo { setBar: function(value) { bar value; } }; spyOn(foo, setBar).and.callThrough(); }); it(can call through and then stub in the same spec, function() { foo.setBar(123); expect(bar).toEqual(123); foo.setBar.and.stub(); bar null; foo.setBar(123); //返回原始的存根 expect(bar).toBe(null); }); }); 在上面这段代码里 要注意 Spies and.callThrough 的用法 注意代码 spyOn(foo, getBar).and.callThrough(); 跟 spyOn(foo, getBar); 的区别 spyOn(foo, getBar).and.callThrough() 会调用实例方法
产生实际的影响而 spyOn(foo, getBar); 只是调用了 Jasmine 保存的这个函数的 存根不会影响到实际的值 如果没看明白请仔细看代码上我添加的注释。 示例8 其他属性 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 describe(A spy, function() { var foo, bar null; //每个对 specs 的调用都会被跟踪并在calls属性上公开 beforeEach(function() { foo { setBar: function(value) { bar value; } }; spyOn(foo, setBar); }); //.calls.any如果spy没有被调用则返回false如果至少有一个调用发生则返回true it(tracks if it was called at all, function() { expect(foo.setBar.calls.any()).toEqual(false); foo.setBar(); expect(foo.setBar.calls.any()).toEqual(true); }); //.calls.count返回调用 specs 的次数 it(tracks the number of times it was called, function() { expect(foo.setBar.calls.count()).toEqual(0); foo.setBar(); foo.setBar(); expect(foo.setBar.calls.count()).toEqual(2); }); //.calls.argsForindex返回传递给调用号索引的参数 it(tracks the arguments of each call, function() { foo.setBar(123); foo.setBar(456, baz); expect(foo.setBar.calls.argsFor(0)).toEqual([123]); expect(foo.setBar.calls.argsFor(1)).toEqual([456, baz]); }); //.calls.allArgs返回所有调用的参数 it(tracks the arguments of all calls, function() { foo.setBar(123); foo.setBar(456, baz); expect(foo.setBar.calls.allArgs()).toEqual([[123],[456, baz]]); }); //.calls.all返回上下文this和传递所有调用的参数 it(can provide the context and arguments to all calls, function() { foo.setBar(123); expect(foo.setBar.calls.all()).toEqual([{object: foo, args: [123], returnValue: undefined}]); }); //.calls.mostRecent返回上一次调用的上下文this和参数 it(has a shortcut to the most recent call, function() { foo.setBar(123); foo.setBar(456, baz); expect(foo.setBar.calls.mostRecent()).toEqual({object: foo, args: [456, baz], returnValue: undefined}); }); //.calls.first返回上下文this和第一次调用的参数 it(has a shortcut to the first call, function() { foo.setBar(123); foo.setBar(456, baz); expect(foo.setBar.calls.first()).toEqual({object: foo, args: [123], returnValue: undefined}); }); //当检查来自allmostRecent和first的返回时当调用 specs 时object属性被设置为this的值。 it(tracks the context, function() { var spy jasmine.createSpy(spy); var baz { fn: spy }; var quux { fn: spy }; baz.fn(123); quux.fn(456); //.object 返回的this ,即调用对象 expect(spy.calls.first().object).toBe(baz); expect(spy.calls.mostRecent().object).toBe(quux); }); //.calls.reset清除 specs 的所有跟踪 it(can be reset, function() { foo.setBar(123); foo.setBar(456, baz); expect(foo.setBar.calls.any()).toBe(true); foo.setBar.calls.reset(); expect(foo.setBar.calls.any()).toBe(false); }); }); // specs createSpy //当没有一个函数来监视jasmine.createSpy可以创建一个“裸” specs 。 //这个 specs 作为任何其他 specs - 跟踪调用参数等但其没有实现。 specs 是JavaScript对象可以这样使用。 describe(A spy, when created manually, function() { var whatAmI; beforeEach(function() { whatAmI jasmine.createSpy(whatAmI); whatAmI(I, am, a, spy); }); it(is named, which helps in error reporting, function() { expect(whatAmI.and.identity()).toEqual(whatAmI); }); it(tracks that the spy was called, function() { expect(whatAmI).toHaveBeenCalled(); }); it(tracks its number of calls, function() { expect(whatAmI.calls.count()).toEqual(1); }); it(tracks all the arguments of its calls, function() { expect(whatAmI).toHaveBeenCalledWith(I, am, a, spy); }); it(allows access to the most recent call, function() { expect(whatAmI.calls.mostRecent().args[0]).toEqual(I); }); }); // specs createSpyObj //为了创建一个有多个 specs 的模拟使用jasmine.createSpyObj并传递一个字符串数组。 它返回一个对象它具有属于 specs 的每个字符串的属性。 describe(Multiple spies, when created manually, function() { var tape; beforeEach(function() { tape jasmine.createSpyObj(tape, [play, pause, stop, rewind]); tape.play(); tape.pause(); tape.rewind(0); }); it(creates spies for each requested function, function() { expect(tape.play).toBeDefined(); expect(tape.pause).toBeDefined(); expect(tape.stop).toBeDefined(); expect(tape.rewind).toBeDefined(); }); it(tracks that the spies were called, function() { expect(tape.play).toHaveBeenCalled(); expect(tape.pause).toHaveBeenCalled(); expect(tape.rewind).toHaveBeenCalled(); expect(tape.stop).not.toHaveBeenCalled(); }); it(tracks all the arguments of its calls, function() { expect(tape.rewind).toHaveBeenCalledWith(0); }); }); //匹配所有与jasmine.any describe(jasmine.anything, function() { //如果实际值不为null或未定义jasmine.anything返回true。 it(matches anything, function() { expect(1).toEqual(jasmine.anything()); }); describe(when used with a spy, function() { it(is useful when the argument can be ignored, function() { var foo jasmine.createSpy(foo); foo(12, function() { return false; }); expect(foo).toHaveBeenCalledWith(12, jasmine.anything()); }); }); }); //与jasmine.objectContaining的部分匹配 //jasmine.objectContaining是用于期望在实际中只关心某些键/值对的时候。 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() { //只比对bar 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.arrayContaining相匹配 //jasmine.arrayContaining用于那些期望只关心数组中的某些值的时候。 describe(jasmine.arrayContaining, function() { var foo; beforeEach(function() { foo [1, 2, 3, 4]; }); it(matches arrays with some of the values, function() { expect(foo).toEqual(jasmine.arrayContaining([3, 1])); expect(foo).not.toEqual(jasmine.arrayContaining([6])); }); describe(when used with a spy, function() { it(is useful when comparing arguments, function() { var callback jasmine.createSpy(callback); callback([1, 2, 3, 4]); expect(callback).toHaveBeenCalledWith(jasmine.arrayContaining([4, 2, 3])); expect(callback).not.toHaveBeenCalledWith(jasmine.arrayContaining([5, 2])); }); }); }); //字符串与jasmine.stringMatching匹配 //jasmine.stringMatching用于当你不想完全匹配较大对象中的字符串时或者匹配 specs 预期中的字符串的一部分。 describe(jasmine.stringMatching, function() { it(matches as a regexp, function() { expect({foo: bar}).toEqual({foo: jasmine.stringMatching(/^bar$/)}); expect({foo: foobarbaz}).toEqual({foo: jasmine.stringMatching(bar)}); }); describe(when used with a spy, function() { it(is useful for comparing arguments, function() { var callback jasmine.createSpy(callback); callback(foobarbaz); expect(callback).toHaveBeenCalledWith(jasmine.stringMatching(bar)); expect(callback).not.toHaveBeenCalledWith(jasmine.stringMatching(/^bar$/)); }); }); }); //定制不对称等式测试器 //当您需要检查某个满足特定标准的条件而不是严格相等时您还可以通过提供具有asymmetricMatch函数的对象来指定自定义非对称等式测试器。 describe(custom asymmetry, function() { var tester { asymmetricMatch: function(actual) { var secondValue actual.split(,)[1]; return secondValue bar; } }; it(dives in deep, function() { expect(foo,bar,baz,quux).toEqual(tester); }); describe(when used with a spy, function() { it(is useful for comparing arguments, function() { var callback jasmine.createSpy(callback); callback(foo,bar,baz); expect(callback).toHaveBeenCalledWith(tester); }); }); }); 示例 9 Jasmine 时钟 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 //Jasmine 时钟 //Jasmine 2.0的此语法已更改。 Jasmine时钟可用于测试时间相关代码。 describe(Manually ticking the Jasmine Clock, function() { var timerCallback; //它安装调用了 jasmine.clock。安装在需要操纵时间的spec或suite。 beforeEach(function() { timerCallback jasmine.createSpy(timerCallback); jasmine.clock().install(); }); //完成恢复原始功能后请务必卸载时钟。 afterEach(function() { jasmine.clock().uninstall(); }); //模拟JavaScript超时函数 //您可以使setTimeout或setInterval同步执行已注册的函数只有当时钟在时间上向前跳过时。 //要执行注册的函数通过jasmine.clock。tick函数延时时间该函数 参数为 毫秒。 it(causes a timeout to be called synchronously, function() { setTimeout(function() { timerCallback(); }, 100); expect(timerCallback).not.toHaveBeenCalled(); jasmine.clock().tick(101); expect(timerCallback).toHaveBeenCalled(); }); it(causes an interval to be called synchronously, function() { setInterval(function() { timerCallback(); }, 100); expect(timerCallback).not.toHaveBeenCalled(); jasmine.clock().tick(101); expect(timerCallback.calls.count()).toEqual(1); jasmine.clock().tick(50); expect(timerCallback.calls.count()).toEqual(1); jasmine.clock().tick(50); expect(timerCallback.calls.count()).toEqual(2); }); //模拟日期 //Jasmine时钟也可以用来模拟当前日期。 describe(Mocking the Date object, function(){ it(mocks the Date object and sets it to a given time, function() { var baseTime new Date(2013, 9, 23); //如果你没有为mockDate提供基准时间它将使用当前日期。 jasmine.clock().mockDate(baseTime); jasmine.clock().tick(50); expect(new Date().getTime()).toEqual(baseTime.getTime() 50); }); }); }); 示例 10 异步支持 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 //异步支持 //Jasmine 2.0的此语法已更改。 Jasmine还支持运行需要测试异步操作的specs(测试用例)。 describe(Asynchronous specs, function() { var value; //调用beforeAllafterAllbeforeEachafterEach和它可以接受一个可选的单个参数当异步工作完成时应该调用。 beforeEach(function(done) { setTimeout(function() { value 0; done(); }, 1); }); //在done函数在调用之前这个specs(测试用例)不会开始。 //这个specs(测试用例)将会等待 beforeEach 调用 done() 后执行。 it(should support async execution of test preparation and expectations, function(done) { value; expect(value).toBeGreaterThan(0); expect(value).toBe(1);//所以这里value 的值为1 done(); }); //默认情况下jasmine将等待5秒钟异步specs(测试用例)在导致超时失败之前完成。 //如果超时在调用done之前超时则当前specs(测试用例)将被标记为失败并且单元测试执行将继续如同调用完成。 //如果特定规则应该更快失败或需要更多时间可以通过向其传递超时值等来调整。 //如果整个单元测试应该有不同的超时则可以在任何给定描述之外全局设置jasmine.DEFAULT_TIMEOUT_INTERVAL。 describe(long asynchronous specs, function() { beforeEach(function(done) { done(); }, 1000); it(takes a long time, function(done) { setTimeout(function() { done(); }, 9000); }, 10000); afterEach(function(done) { done(); }, 1000); }); //done.fail函数使specs(测试用例)失败并指示它已完成 describe(A spec using done.fail, function() { var foo function(x, callBack1, callBack2) { if (x) { setTimeout(callBack1, 0); } else { setTimeout(callBack2, 0); } }; it(should not call the second callBack, function(done) { foo(true, done, function() { done.fail(Second callback has been called); } ); }); }); }); 示例11 自定义matcher 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 //通常项目将要封装用于跨多个规范的自定义匹配代码。 下面是如何创建一个Jasmine兼容的自定义匹配器。 //在其根部的自定义匹配器是比较函数其获取实际值和期望值。 //这个工厂被传递给Jasmine理想的情况是调用beforeEach并且在一个给定的调用中描述的所有规范的范围内。 //定制匹配器在规格之间拆分。 工厂的名称将是在期望的调用的返回值上暴露的匹配器的名称。 var customMatchers { //自定义匹配器工厂传递两个参数util它有一组用于匹配器使用的效用函数见matchersUtil.js用于当前列表和customEqualityTesters //如果util.equals被调用则需要传递。 当调用匹配器时可以使用这些参数。 toBeGoofy: function (util, customEqualityTesters) { //工厂方法应该返回一个含有比较函数的对象该函数将被调用以检查期望值。 return { //比较函数第一个参数为实际值 ,第二个参数传递给匹配器本身的值如果有的话。 compare: function (actual, expected) { //toBeGoofy接受一个可选的期望参数所以如果不传递在这里定义。 if (expected undefined) { expected ; } var result {}; if (result.pass) { //如果未定义期望将尝试为匹配器创建失败消息。 但是如果返回值具有message属性它将用于失败的期望。 result.message Expected actual not to be quite so goofy; } else { //匹配成功所以自定义失败消息应该出现在负期望的情况下 - 当期望与.not一起使用时。 result.message Expected actual to be goofy, but it was not very goofy; } return result; } }; } }; //调用代码 describe(Custom matcher: toBeGoofy, function() { beforeEach(function() { jasmine.addMatchers(customMatchers); }); it(is available on an expectation, function () { expect({ hyuk: gawrsh }).toBeGoofy(); }); it(can take an expected parameter, function () { expect({ hyuk: gawrsh is fun }).toBeGoofy(is fun); }); it(can be negated, function () { expect({ hyuk: this is fun }).not.toBeGoofy(); }); }); 看完上面的示例应该在项目中应用没有什么问题了。 文章转载自: http://www.morning.fqyqm.cn.gov.cn.fqyqm.cn http://www.morning.gfqjf.cn.gov.cn.gfqjf.cn http://www.morning.cokcb.cn.gov.cn.cokcb.cn http://www.morning.qqrlz.cn.gov.cn.qqrlz.cn http://www.morning.lwsct.cn.gov.cn.lwsct.cn http://www.morning.rqgq.cn.gov.cn.rqgq.cn http://www.morning.jpydf.cn.gov.cn.jpydf.cn http://www.morning.hyryq.cn.gov.cn.hyryq.cn http://www.morning.lfdzr.cn.gov.cn.lfdzr.cn http://www.morning.tbqbd.cn.gov.cn.tbqbd.cn http://www.morning.chehb.com.gov.cn.chehb.com http://www.morning.kxscs.cn.gov.cn.kxscs.cn http://www.morning.xhlht.cn.gov.cn.xhlht.cn http://www.morning.ruyuaixuexi.com.gov.cn.ruyuaixuexi.com http://www.morning.qnftc.cn.gov.cn.qnftc.cn http://www.morning.mxmtt.cn.gov.cn.mxmtt.cn http://www.morning.rqxtb.cn.gov.cn.rqxtb.cn http://www.morning.rzrbw.cn.gov.cn.rzrbw.cn http://www.morning.jthjr.cn.gov.cn.jthjr.cn http://www.morning.lynb.cn.gov.cn.lynb.cn http://www.morning.bwygy.cn.gov.cn.bwygy.cn http://www.morning.ldfcb.cn.gov.cn.ldfcb.cn http://www.morning.rnxs.cn.gov.cn.rnxs.cn http://www.morning.cmrfl.cn.gov.cn.cmrfl.cn http://www.morning.mynbc.cn.gov.cn.mynbc.cn http://www.morning.ykrkq.cn.gov.cn.ykrkq.cn http://www.morning.ssjry.cn.gov.cn.ssjry.cn http://www.morning.ldwxj.cn.gov.cn.ldwxj.cn http://www.morning.cybch.cn.gov.cn.cybch.cn http://www.morning.hqrr.cn.gov.cn.hqrr.cn http://www.morning.qwdqq.cn.gov.cn.qwdqq.cn http://www.morning.nrfqd.cn.gov.cn.nrfqd.cn http://www.morning.zrgdd.cn.gov.cn.zrgdd.cn http://www.morning.rqlzz.cn.gov.cn.rqlzz.cn http://www.morning.ppzgr.cn.gov.cn.ppzgr.cn http://www.morning.ktmbr.cn.gov.cn.ktmbr.cn http://www.morning.nfnxp.cn.gov.cn.nfnxp.cn http://www.morning.rngyq.cn.gov.cn.rngyq.cn http://www.morning.dmzmy.cn.gov.cn.dmzmy.cn http://www.morning.gwzfj.cn.gov.cn.gwzfj.cn http://www.morning.lyhry.cn.gov.cn.lyhry.cn http://www.morning.sgfpn.cn.gov.cn.sgfpn.cn http://www.morning.qrgfw.cn.gov.cn.qrgfw.cn http://www.morning.bnygf.cn.gov.cn.bnygf.cn http://www.morning.mzskr.cn.gov.cn.mzskr.cn http://www.morning.snygg.cn.gov.cn.snygg.cn http://www.morning.llxyf.cn.gov.cn.llxyf.cn http://www.morning.rtsx.cn.gov.cn.rtsx.cn http://www.morning.cbtn.cn.gov.cn.cbtn.cn http://www.morning.mhfbp.cn.gov.cn.mhfbp.cn http://www.morning.tkcct.cn.gov.cn.tkcct.cn http://www.morning.wqbrg.cn.gov.cn.wqbrg.cn http://www.morning.ypmqy.cn.gov.cn.ypmqy.cn http://www.morning.zybdj.cn.gov.cn.zybdj.cn http://www.morning.rfbt.cn.gov.cn.rfbt.cn http://www.morning.nyqm.cn.gov.cn.nyqm.cn http://www.morning.hxwhyjh.com.gov.cn.hxwhyjh.com http://www.morning.nkhdt.cn.gov.cn.nkhdt.cn http://www.morning.ngmjn.cn.gov.cn.ngmjn.cn http://www.morning.cqwb25.cn.gov.cn.cqwb25.cn http://www.morning.ltpzr.cn.gov.cn.ltpzr.cn http://www.morning.dmtbs.cn.gov.cn.dmtbs.cn http://www.morning.jhrlk.cn.gov.cn.jhrlk.cn http://www.morning.dpflt.cn.gov.cn.dpflt.cn http://www.morning.mtymb.cn.gov.cn.mtymb.cn http://www.morning.rqkk.cn.gov.cn.rqkk.cn http://www.morning.cbpkr.cn.gov.cn.cbpkr.cn http://www.morning.crsnb.cn.gov.cn.crsnb.cn http://www.morning.qqnjr.cn.gov.cn.qqnjr.cn http://www.morning.wcqxj.cn.gov.cn.wcqxj.cn http://www.morning.cnvlog.cn.gov.cn.cnvlog.cn http://www.morning.bmts.cn.gov.cn.bmts.cn http://www.morning.lsfzq.cn.gov.cn.lsfzq.cn http://www.morning.qllcp.cn.gov.cn.qllcp.cn http://www.morning.bljcb.cn.gov.cn.bljcb.cn http://www.morning.mcjp.cn.gov.cn.mcjp.cn http://www.morning.rnngz.cn.gov.cn.rnngz.cn http://www.morning.zxqxx.cn.gov.cn.zxqxx.cn http://www.morning.lkhgq.cn.gov.cn.lkhgq.cn http://www.morning.qkqjz.cn.gov.cn.qkqjz.cn