Jasmine是什么
Jasmine是一個Javascript BDD測試框架。只要是Javascript能運行的地方,都可以運行jasmine
安裝方法
Local installation npm install --save-dev jasmine
Global installation npm install -g jasmine
安裝之后可以使用下面命令來初始化項目 jasmine init
。使用這個命令會創建 ./spec/support這樣一個目錄,然后會在support下有jasmine.json
這樣一個配置文件
jasmine.json
是用來配置jasmine runner的,比如我可以再里面寫上需要運行的測試文件是哪些
一個簡單的jasmine.json
的內容如下
{
"spec_dir": "spec",
"spec_files": [
"**/*[sS]pec.js"
],
"helpers": [
"helpers/**/*.js"
],
"stopSpecOnExpectationFailure": false,
"random": false
}
通過設置環境變量也可以自定義jasmine.json
.
jasmine JASMINE_CONFIG_PATH=relative/path/to/your/jasmine.json
使用命令jasmine
來運行測試套件
Suites: describe your tests and Specs
jasmine的全局方法 describe()
代表著測試套件test suite的實現。
describe(string, function)
方法有兩個參數
- string指整個測試套件的名字或是title
- function指整個測試套件的實現代碼
jasmine的全局方法 it()
代表著測試用例/測試規格test specs的實現。
it(string, function)
方法有兩個參數
- string指整個測試規格的名字或是title
- function指整個測試規格的實現代碼/測試代碼
一個測試規格里面包含著至少一個驗證期望的代碼。只有當所有的expectation(assertion)通過了,才表明這個測試規格通過了。只要一個失敗的expectation,測試規格就不通過
下面的代碼還表明任何在describe里面聲明的變量都可以再it中使用
describe("A suite is just a function", function() {
var a;
it("and so is a spec", function() {
a = true;
expect(a).toBe(true);
});
});
Expectations
在jasmine中,expectation就是一個assertion,結果要嘛為true
要嘛為false
在jasmine中,expectation是用方法expect(actual_value)
實現的. 給expect傳入的應該是系統實際運行出來的值。
expect方法與Matcher方法鏈接,而Matcher方法接受的是期待結果,于是一句expectation可以寫成
it("and has a positive case", function() {
expect(true).toBe(true);
});
toBe()
就是Matcher方法。Matcher方法實現了期待值和實際結果值的比較,并把布爾型的比較結果報告給jasmine,然后jasmine再來判斷一個測試pass或是fail
通過在Matcher方法前面使用not,可以得到一個negative assertion
it("and can have a negative case", function() {
expect(false).not.toBe(true);
});
});
jasmine提供了非常豐富的Matchers。jasmine還提供custom matchers來滿足項目特殊需求
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;
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()方法來讓一個spec失敗。
fail()
的參數可以是一個failure message或是Error object
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()
使用describe()
來組織相關的specs可以幫助整個specs有BDD的style從而易讀易懂,也可以幫助每一個spec有自己獨一無二的命名以便于搜索
通常一個specs的命名是由describe的名字加上it的名字,我們可以像下面這個例子一樣命名
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);
});
});
通常一個specs的命名是由describe的名字加上it的名字,我們可以像下面這個例子一樣命名
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);
});
});
setup and teardown
像大部分測試框架一樣,jasmine也提供setup和teardown的功能來在測試前設置的環境狀態設置和測試執行后的清理工作。
jasmine提供的是全局beforeEach()
, afterEach()
, beforeAll()
和afterAll()
方法
beforeEach()
和afterEach()
會在每個spec前后執行
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()
和afterAll()
會在所有spec前后執行。不過,我們要小心使用這兩個方法因為他們不會再spec之間充值狀態。
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);
});
});
this 關鍵字
我們可以通過在describe
里面設置全局變量來傳遞此變量到it()
中。而在beforeEach
, it
和afterEach
中我們可以通過this關鍵字來分享變量。但是對下一個beforeEach
, it
和afterEach
this
關鍵字都會被重置為empty file
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);
expect(this.bar).toBe(undefined);
});
});
可內嵌的describe
一個describe可以內嵌到一個describe中的任何specs級別的位置
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);
});
});
});
skip describe
如果想要一個測試套件不被執行,可以使用 xdescribe()
方法。使用了xdescribe之后,相應的測試套件和specs就不被執行
xdescribe("A spec", function() {
var foo;
beforeEach(function() {
foo = 0;
foo += 1;
});
it("is just a function, so it can contain any code", function() {
expect(foo).toEqual(1);
});
});
Pending Spec
通過使用xit可以讓spec處于一個pending的狀態,這個spec不會run但是相關信息會在result中顯示為pending
除了使用xit,如果一個spec沒有function參數傳入的時候也會被標記為pending
如果在spec內部使用pending方法,無論內部expectation如何,這個spec都會被標記為pending。pending方法接受一串字符串作為參數來表示pending的理由,這個字符串會顯示在最終的測試執行結果里
describe("Pending specs", function() {
xit("can be declared 'xit'", function() {
expect(true).toBe(false);
});
it("can be declared with 'it' but without a function");
it("can be declared by calling 'pending' in the spec body", function() {
expect(true).toBe(false);
pending('this is why it is pending');
});
});
Test Spies
jasmine支持一個test double叫spies。 一個spy是一個test stub,能夠記錄一個方法的調用情況和參數情況。spy只存在describe和it中,然后會在每一個spec之后被刪除。
使用spyOn來設置track的方法,被track的方法不會被執行
-
toHaveBeenCalled
Matcher會返回true如果spy被調用 -
toHaveBeenCalledTimes
Matcher會比對spy被調用的次數 -
toHaveBeenCalledWith
Matcher會返回true如果參數列表 match 被記錄的調用
describe("A spy", function() {
var foo, bar = null;
beforeEach(function() {
foo = {
setBar: function(value) {
bar = value;
}
};
spyOn(foo, 'setBar');
foo.setBar(123);
foo.setBar(456, 'another param');
});
it("tracks that the spy was called", function() {
expect(foo.setBar).toHaveBeenCalled();
});
it("tracks that the spy was called x times", function() {
expect(foo.setBar).toHaveBeenCalledTimes(2);
});
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() {
expect(bar).toBeNull();
});
});
Spies: and.callThrough
使用spyOn().and.callThrough
除了記錄被調用的信息,而且還可以讓被track的方法真實的執行
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() {
expect(fetchedBar).toEqual(123);
});
});
Spies: and.returnValue
使用spyOn().and.returnValue
可以讓被調用的方法返回固定的值
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);
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);
});
});
Spies: and.returnValues
使用spyOn().and.returnValues
可以讓被調用的方法按順序連續地返回固定的值,最后一個值為undefined
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() {
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();
});
});
Spies: and.callFake
使用spyOn().and.callFake(function(){return ...})
可以讓被調用的方法轉為執行callFake()
里面提供的方法
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);
});
});
Spies: and.throwError
使用spyOn().and.throwError
可以讓被調用的方法返回一個指定的異常
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");
});
});
Spies: and.stub
當一個spy使用了spyOn().and.callThrough()
,我們可以在一個spec中使用and.stub隨時返回原始的stubbing行為
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);
});
});
Other tracking properties
每次對spy的調用,調用的相關信息都會被暴露和跟蹤到calls屬性里面
describe("A spy", function() {
var foo, bar = null;
beforeEach(function() {
foo = {
setBar: function(value) {
bar = value;
}
};
spyOn(foo, 'setBar');
});
.calls.any()
會返回false如果spy沒有被調用過,返回true如果spy至少被調用一次
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()
會返回spy被調用的次數
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)
會返回傳給spy的參數,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()
會返回所有調用的the context(the 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()
會返回最近一次調用的the context(the 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()
會返回第一次調用的the context(the 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()
返回值中的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);
expect(spy.calls.first().object).toBe(baz);
expect(spy.calls.mostRecent().object).toBe(quux);
});
.calls.reset()
會重置所有spy的tracking
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);
});
});
Spies: createSpy
當沒有一個function需要spy on的時候,jasmine.createSpy 能創建一個”bare” spy。這個spy也能和其他spy一樣能夠tracking calls和參數等。但是這個spy背后沒有什么具體實現,就像使用一個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");
});
});
Spies: createSpyObj
為了創建多個spies,可以使用jasmine.createSpyObj,這個方法接受一個字符串數組,返回一個對象,這個對象的各個屬性就是spy,名稱就是字符串數組里面的字符串
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);
});
});
Matching Anything with jasmine.any
jasmine.any
接受一個類型或是constructor作為參數也是期待結果。這個方法用于真實結果和期待結果在類型level上的比較
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));
});
});
});
Matching existence with jasmine.anything
jasmine.anything
返回true如果真實結果是非null或是undefined
describe("jasmine.anything", function() {
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());
});
});
});
Partial Matching with 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() {
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
}));
});
});
});
Partial Array Matching with 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]));
});
});
});
String Matching with jasmine.stringContaining
jasmine.stringContaining
用于字符串的判斷
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$/));
});
});
});
Custom asymmetric equality tester
當你需要檢查符合一定標準的結果的時候,不是嚴格相等,可以制定一個通過提供一個對象,這個對象里面包含asymmetricMatch function來實現custom asymmetric equality tester
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);
});
});
});
Jasmine Clock
Jasmine Clock用于測試時間依賴的代碼。在spec或是suite中使用jasmine.clock().install
來操作時間
記得使用jasmine.clock().uninstall
來恢復。
describe("Manually ticking the Jasmine Clock", function() {
var timerCallback;
beforeEach(function() {
timerCallback = jasmine.createSpy("timerCallback");
jasmine.clock().install();
});
afterEach(function() {
jasmine.clock().uninstall();
});
Mocking the JavaScript Timeout Functions
使用setTimeout或是setInterval同步執行registered functions,使用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 Clock也可以用于mock date
如果不提供一個時間,就會使用current date
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);
jasmine.clock().mockDate(baseTime);
jasmine.clock().tick(50);
expect(new Date().getTime()).toEqual(baseTime.getTime() + 50);
});
});
});
Asynchronous Support
調用beforeAll
, afterAll
, beforeEach
, afterEach
和it
時,可以傳入單個參數,這個參數被調用的時候就代表著一步操作的結束
describe("Asynchronous specs", function() {
var value;
beforeEach(function(done) {
setTimeout(function() {
value = 0;
done();
}, 1);
});
spec不會開始執行直到done function在beforeEach中調用。spec也不會結束直到spec的done函數被調用
it("should support async execution of test preparation and expectations", function(done) {
value++;
expect(value).toBeGreaterThan(0);
done();
});
jasmine對異步操作的spec的默認時間5秒,超過5秒就會引起timeout failure。如果timeout在done被調用之前過期,current spec會被mark為failed,suite繼續執行
如果需要使spec fail faster或是延長時間,我們可以調整傳給it方法的時間
如果想改變整個suite的timeout,我們設置jasmine.DEFAULT_TIMEOUT_INTERVAL,這個變量是全局的,超越任何describe
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);
});
如果需要使spec fail faster或是延長時間,我們可以調整傳給it方法的時間
done.fail
function會fail spec
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");
}
);
});
});
});