前端测试框架 jasmine 的使用
?????? 最近的項目在使用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文件加載順序
???
<!DOCTYPE html> <html> <head><meta charset="utf-8"><title>Jasmine Spec Runner v2.5.2</title><link rel="shortcut icon" type="image/png" href="lib/jasmine-2.5.2/jasmine_favicon.png"><link rel="stylesheet" href="lib/jasmine-2.5.2/jasmine.css"><script src="lib/jasmine-2.5.2/jasmine.js"></script><script src="lib/jasmine-2.5.2/jasmine-html.js"></script><script src="lib/jasmine-2.5.2/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>?
??? 我們直接運行 SpecRunner.html? 測試結果如下:
5個 specs,0個失敗,全部通過。在 PlayerSpec.js 里添加一個Suite,看看報錯是什么樣的。
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
??
//測試集 開始于調用全局Jasmine函數describe,有兩個參數:一個字符串和一個函數。 //該字符串是specs(測試用例)單元測試的名稱或標題 - 通常是被測試的。 該函數是一個實現單元測試的代碼塊。describe("A suite", function() {it("contains spec with an expectation", function() {expect(true).toBe(true);}); });?
示例2?? ???? 包含多個斷言
?
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嵌套
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 的 X(2) 次方 / 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?? beforeEach,afterEach,beforeAll和afterAll函數
//顧名思義,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
//this關鍵字//另一種在beforeEach,it和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);//注意這里的區別 undefinedexpect(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 待定規則
//待定規則 //待處理的規則不會運行,但它們的名稱將在結果中顯示為待處理。 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 對象監控
// 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() 函數都返回 745fetchedBar = 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?? 其他屬性
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.argsFor(index):返回傳遞給調用號索引的參數 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});});//當檢查來自all(),mostRecent()和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() {//只比對barexpect(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 時鐘
//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?? 異步支持
//異步支持 //Jasmine 2.0的此語法已更改。 Jasmine還支持運行需要測試異步操作的specs(測試用例)。 describe("Asynchronous specs", function() {var value;//調用beforeAll,afterAll,beforeEach,afterEach和它可以接受一個可選的單個參數,當異步工作完成時,應該調用。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 的值為1done();});//默認情況下,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?
//通常,項目將要封裝用于跨多個規范的自定義匹配代碼。 下面是如何創建一個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();}); });?看完上面的示例應該在項目中應用沒有什么問題了。
轉載于:https://www.cnblogs.com/fengh/p/6121846.html
總結
以上是生活随笔為你收集整理的前端测试框架 jasmine 的使用的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 21天学通C语言-学习笔记(4)
- 下一篇: 2019年3月未来教育计算机二级题库,2