2017-04-07 24 views
1

我有麻煩測試數據輪詢在我的控制器如何使用Jasmine測試AngularJS上的數據輪詢?

控制器的邏輯是這樣的

$onInit() { 
    this.requestRootLocations(); 
    this.startDataPolling(); 
} 

private startDataPolling() { 

    this.stop = this.$interval(() => 
    this.requestRootLocations() 
    , this.DATA_POLLING_INTERVAL); 
} 

private requestRootLocations() { 
     this.locationsService.requestRootElements().then(function (locationItem) { 
     ... 

     this.entityList = (locationItem["locations"] instanceof Array) ? locationItem["locations"] : []; 
     }.bind(this), function() { 
     console.log("Error on loading locations data."); 
     }); 
    } 

更新: 在服務HTTP請求:

public requestRootElements() { 
     return this.$http.get(this.API + "locations").then((response) => response.data); 
    } 

這工作正常像預期一樣。

測試用例看起來像這樣

it("should call http request on intervals", function() { 

    ctrl.$onInit(); 
    $httpBackend.whenGET(api + "locations").respond(200, locationData); 

    // advance in time by 1 seconds 
    $interval.flush(1000); 

    $httpBackend.expectGET(api + "locations"); 
    // after 1 seconds locations should be called once 
    $httpBackend.flush(); 

    expect(ctrl.counts.length).toBe(4); 
    expect(ctrl.entities.length).toBe(6); 

    $interval.flush(dataPollingInterval); 
    $httpBackend.expectGET(api + "locations"); //does not work, why? 
    $httpBackend.flush(); 

    // after the second call the data should be the same in this case 
    expect(ctrl.counts.length).toBe(4); 
    expect(ctrl.entities.length).toBe(6); 
}); 

但在第二expectGET是錯誤

Error: Unsatisfied requests: GET /apiv1/locations

+0

這些$ http請求在哪裏?發佈截斷的代碼片段不會有幫助。如果這發生在控制器中,請將其完整發布。如果這發生在服務中,請發佈控制器和服務。 – estus

+0

謝謝,我已更新問題 – Juri

+0

仍不確定爲什麼失敗。對於初學者來說,DATA_POLLING_INTERVAL不是1000。真正的問題是幾個單元混合成一個集成測試,並不是很有效。它引入了太多的移動部件,並沒有測試任何不能同時獨立測試的東西。看到答案。 – estus

回答

0

這裏的問題是,單位不是孤立的。這是集成測試(控制器+服務+ $間隔),而不是單元測試。當測試變成紅色時,不可能說出哪個單元失敗。

單元測試的正確策略是模擬所有測試單元(控制器)。 $interval也可以選擇性地模擬,我們並不需要測試它的工作原理 - 這已經由Angular測試過了。

constructor(...) { 
    ... 
    // bind callback method 
    this.dataPollingHandler = this.dataPollingHandler.bind(this); 
} 

$onInit() { 
    this.requestRootLocations(); 
    this.stop = this.$interval(this.dataPollingHandler, this.DATA_POLLING_INTERVAL); 
} 

private dataPollingHandler() { 
    this.requestRootLocations() 
} 

它可以像

spyOn(ctrl, 'requestRootLocations'); 

// unbind callback method 
ctrl.dataPollingHandler.call(null); 

expect(ctrl.requestRootLocations).toHaveBeenCalled(); 

... 

var intervalPromise = $q.resolve(); 
var intervalMock = jasmine.createSpy().and.returnValue(intervalPromise); 
var ctrl = $controller(..., { $interval: intervalMock }); 

ctrl.$onInit(); 
expect(ctrl.stop).toBe(intervalPromise); 
expect($intervalStub).toHaveBeenCalledWith(ctrl.dataPollingHandler, 1000); 

... 

var locationsServiceMock = { 
    requestRootLocations: jasmine.createSpy().and.returnValue($q.resolve(locationData)); 
} 

var ctrl = $controller(..., { locationsService: locationsServiceMock }); 
// now ctrl.requestRootLocations can be tested 
... 

它是確定具有該套件中既單元和集成測試進行測試,但是,當存在適當的控制器和服務單元測試,集成測試變得多餘。

+0

你是完全正確的。但這不是我希望得到的答案。這是一個集成測試,並在幾小時後或嘗試運行: $ httpBackend.expectGET(api +「locations」); $ interval.flush(1000); $ httpBackend.flush();期望(ctrl.isEditing).toBe(false); //第一次間隔後應該叫一個請求 $ httpBackend.expectGET(api +「locations」); $ interval.flush(dataPollingInterval); $ httpBackend.flush(); – Juri

+0

很高興它爲你工作,把後臺期待後的間隔沖洗是有道理的。但正如所說的那樣,測試這樣的間隔是沒有意義的。它已經被Angular測試過了,你可以肯定它可以按預期工作。這種集成測試通常不應該寫出來,因爲它們不能代替單元測試,也不會使覆蓋範圍受益。 – estus

+0

希望這有助於。提問者希望得到「如何測試......」的答案或僅僅是修正錯誤並不總是很清楚。 – estus

相關問題