angular2 學習筆記 ( unit test 單元測試 )

更新 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 的哦. 

相關文章
相關標籤/搜索