製作,這不是在角1.x的單元/集成測試結果的誤差$httpBackend.when
嘲笑的請求:製作到HTTP服務器請求實際在AngularJS單元/集成測試
Error: Unexpected request: GET /real-request
是否有可能使用ngMock
和Karma + Jasmine測試裝備製作真正的HTTP請求?什麼是一個很好的做法呢?
製作,這不是在角1.x的單元/集成測試結果的誤差$httpBackend.when
嘲笑的請求:製作到HTTP服務器請求實際在AngularJS單元/集成測試
Error: Unexpected request: GET /real-request
是否有可能使用ngMock
和Karma + Jasmine測試裝備製作真正的HTTP請求?什麼是一個很好的做法呢?
AngularJS是一個自發的框架,它在單元測試中對HTTP請求的看法是它們都應該被嘲笑。
出於兩個原因,不建議在單元測試中執行真正的HTTP請求。單元測試應該是孤立的,速度很快。提出真正的請求會使測試異步,從而顯着降低測試運行速度。提出真正的請求會打破隔離,測試通過的事實取決於被測試單元和後端。
設計了AngularJS ngMock
模塊(在angular-mocks.js的單元測試中自動加載)時考慮了這一點。開發人員幾乎不會這樣做asynchronous用Angular進行Jasmine單元測試,因爲沒有必要那麼做。
集成測試不同。它們可能不像E2E測試那樣廣泛(通常由Protractor運行),並測試幾個單元如何協同工作,這可能包括後端(HTTP服務器)。所以最終Karma和Jasmine仍在使用,但測試可能會比較慢並且異步,並且會執行真正的HTTP請求。
這是ngMockE2E
模塊(通常用於E2E測試)踢入。它包含在angular-mocks.js中,並與ngMock
並列,但默認情況下未加載。
The ngMockE2E is an AngularJS module which contains mocks suitable for end-to-end testing. Currently there is only one mock present in this module - the e2e $httpBackend mock.
ngMockE2E
包含不同$httpBackend
實現可用於該目的。其API不盡相同。它不應該使用flush
和extend
方法。如果有$q
承諾鏈應該執行,則可以使用$rootScope.$digest()
。
ngMockE2E
將開箱即用,因爲正在對角服務所做的調整適當的通過ngMock
當它的輔助功能module
和inject
使用不起作用。對於一體化測試一個輔助模塊,可以用來代替:
angular.module('ngMockI9n', []).config(function ($provide) {
// hack to restore original implementations which were overridden by ngMock
angular.injector(['ng', function ($httpBackendProvider, $browserProvider) {
$provide.provider('$httpBackend', $httpBackendProvider);
$provide.provider('$browserI9n', $browserProvider);
}]);
// make ngMockE2E $httpBackend use original $browser
var httpBackendI9nDecorator = angular.mock.e2e.$httpBackendDecorator
.map(function (dep) {
return (dep === '$browser') ? '$browserI9n' : dep;
});
$provide.decorator('$httpBackend', httpBackendI9nDecorator);
});
此外,對於whitelisted real HTTP requests配方可以用來使測試更容易,但最好的做法是明確地列舉真實和嘲笑的請求。
beforeEach(module('app'));
beforeEach(module('ngMockI9n'));
beforeEach(inject(function ($httpBackend) {
$httpBackend.when('GET', '/mocked-request').respond(200, {});
// all other requests will be automatically whitelisted and treated as real
// so make sure that mocked requests are mocked above this point
angular.forEach(['GET', 'DELETE', 'JSONP', 'HEAD', 'PUT', 'POST', 'PATCH'],
function (method) {
$httpBackend.when(method).passThrough();
});
}));
it('does real async request', function (done) {
// async tests need extra `done` param
inject(function() {
$http.get('real-request').then(function (response) {
expect(response.data).toEqual(...);
})
.then(done, done.fail);
$rootScope.$digest();
});
});
it('does mocked sync request', function (done) {
// tests with mocked requests are async, too
inject(function() {
$http.get('mocked-request').then(function (response) {
expect(response.data).toEqual(...);
})
.then(done, done.fail);
$rootScope.$digest();
});
});
TL; DR:使用$httpBackend
在集成測試的實際要求ngMockE2E
,這需要一些額外的工作,使其與ngMock
兼容。從不在單元測試中做出真正的請求,這會導致緩慢且垃圾的測試。
請解釋一下在你的情況下什麼是「真正的」HTTP請求? – lin
真正的請求是調用window.XMLHttpRequest並向HTTP服務器發出請求的請求。這在Angular單元測試中不被設計所允許。 – estus
@lin這是自我回答,順便說一句。我認爲這是一個臭名昭着的問題。 – estus