更新 2018-06-03框架
spy object 異步
當組件或則服務有對其它服務依賴的時候,咱們一般會把這些依賴寫成 spy 或則叫 fake.async
爲何這樣作的呢 ? ide
主要的緣由是咱們不該該依賴具體的代碼,假設具體的代碼錯了,咱們這個服務也會跟着報錯. 單元測試
因此單元測試的 "單元",就是說咱們必須把咱們要測試的東西獨立放到一個測試環境裏頭,對外部任何依賴都作隔離. 測試
若是報錯,那麼必定是它錯了,絕對不能是由於被其它人影響而報錯. 因此咱們必須把依賴的服務都寫成 spy.this
describe('SecondService', () => { let firstServiceSpy: jasmine.SpyObj<FirstService>; // 定義依賴的服務 beforeEach(() => { firstServiceSpy = jasmine.createSpyObj('firstService', ['getValue']); //建立假的服務 firstServiceSpy.getValue.and.returnValue('firstValue'); // 直接設定返回的結果 (這樣無論這個服務的具體實現正不正確, 咱們都不會被影響到) TestBed.configureTestingModule({ providers: [ SecondService, { provide: FirstService, useValue: firstServiceSpy } // 替換掉 provide 就能夠了 ] }); }); it(`getValue should return 'firstValueSecondValue'`, inject([SecondService], (secondService : SecondService) => { expect(secondService.getValue()).toBe('firstValuesecondValue'); })); });
第一次寫單元測試.url
之前一直都有據說 TDD 的事情. spa
今天總算是去嘗試了一下. debug
先說說 TDD 的想法, 是這樣的,
開發項目的流程 : 肯定需求 -> 寫類,接口,方法的名字(不寫具體實現代碼哦) -> 寫測試代碼 -> 這時測試的話必定是所有 fail 由於實現代碼還沒寫嘛 -> 寫實現代碼 -> 運行測試 ...
這樣的流程適合須要敏捷開發的項目, 若是你的項目常常須要擴展, 並且擴展每每是不在預計範圍內的, 那麼你必然須要使用敏捷開發模式和流程.
也只有把測試寫好,之後代碼修改了之後纔不須要人工的再去測試一遍.
倒過來看的話,若是你的項目邏輯簡單,擴展老是在預計範圍呢, 那麼你硬去搞敏捷開發寫測試代碼的話,就有點浪費了.
angular 框架支持測試. 使用 karma , jasmine, cli 來跑。
我的以爲要寫的好測試, 對 angular 的依賴注入機制要有點基礎.
一般咱們會測試的東西是 component 和 service.
記得不是因此的東西都要測試的,就好像數學考試同樣, 不須要每一題都 double check, 只測試那些容易出錯的地方就能夠了.
那什麼地方容易出錯呢. 這個因人而異, 看你本身的經驗.
我我的的建議是測試那些關係比較多和複雜的地方.
好比咱們要測試 component
咱們須要先把 component 的依賴準備好,好比 component 依賴的服務.
beforeEach(() => { TestBed.configureTestingModule({ imports: [StoogesModule], declarations: [ SimpleComponent ], providers: [ MockBackend, BaseRequestOptions ] }); TestBed.overrideComponent(SimpleComponent, { set: { providers: [ { provide: Http, deps: [ MockBackend, BaseRequestOptions ], useFactory: (backend: XHRBackend, defaultOptions: BaseRequestOptions) => { return new Http(backend, defaultOptions); } } ] } }); TestBed.compileComponents(); this.fixture = TestBed.createComponent(SimpleComponent); this.com = this.fixture.debugElement.componentInstance; });
TestBed.configureTestingModule 是讓咱們寫準備環境的. 它和 NgModule 差很少.
MockBackend 是模擬 http 數據用的
TestBed.overrideComponent 這個方法用來覆蓋組件定義好的 provider
it("test", async(inject([MockBackend], (backend: MockBackend) => { const mockResponse = { data: [ { id: 0, name: 'Video 0' }, { id: 1, name: 'Video 1' }, { id: 2, name: 'Video 2' }, { id: 3, name: 'Video 3' }, ] }; backend.connections.subscribe((connection) => { console.log("test"); connection.mockRespond(new Response(new ResponseOptions({ body: JSON.stringify(mockResponse) }))); }); let com = this.com as SimpleComponent; com.dada().subscribe(v => { expect("haha").toBe("haha"); }); })));
async() 是幫助咱們寫異步的, 放在 It 的方法裏面就好了
inject() 天然是依賴注入 service 咯, 這個寫法是否是讓你想起了 ng1 ?
backend.connections 是攔截全部的請求, 咱們進一步判斷 connection request url 來作出不一樣的 response data.
能夠看出來,主要的代碼都是爲了搭建環境. 經過依賴注入去覆蓋原有的 provider.
咱們在看看 service.spec.ts
describe("test", () => { beforeEach(() => { TestBed.configureTestingModule({ providers: [ SimpleService ] }); }); it("test1", async(inject([SimpleService], async (simple: SimpleService) => { let data = await simple.getData(); console.log("a"); expect(data).toBe("a"); }))); });
這個比較簡單, 由於不用 create component and override component provider.
寫 await async 也是 ok 的哦.