問題描述
我有一個控制器,它公開了一個函數,該函數在休息調用后返回一些文本.它工作正常,但我無法用 Jasmine 測試它.測試中 Promise 處理程序中的代碼永遠不會執行.
I have a controller that expose a function that returns some text after a rest call. It works fine, but I'm having trouble testing it with Jasmine. The code inside the promise handler in the test never executes.
控制器:
/* global Q */
'use strict';
angular.module('myModule', ['some.service'])
.controller('MyCtrl', ['$scope', 'SomeSvc', function ($scope, SomeSvc) {
$scope.getTheData = function (id) {
var deferred = Q.defer();
var processedResult = '';
SomeSvc.getData(id)
.then(function (result) {
//process data
processedResult = 'some stuff';
deferred.resolve(processedResult);
})
.fail(function (err) {
deferred.reject(err);
});
return deferred.promise;
}
}]);
測試:
describe('some tests', function() {
var $scope;
var $controller;
var $httpBackend;
beforeEach(function() {
module('myModule');
inject(function(_$rootScope_, _$controller_, _$httpBackend_) {
$scope = _$rootScope_.$new();
$controller = _$controller_;
$httpBackend = _$httpBackend_;
//mock the call that the SomeSvc call from the controller will make
$httpBackend.expect('GET', 'the/url/to/my/data');
$httpBackend.whenGET('the/url/to/my/data')
.respond({data:'lots of data'});
$controller ('MyCtrl', {
$scope: $scope
});
});
});
describe('test the returned value from the promise', function() {
var prom = $scope.getTheData(someId);
prom.then(function(result) {
expect(result).toBe('something expected'); //this code never runs
})
});
});
推薦答案
除非調用 promise 回調,否則 then
中的任何內容都不會運行 - 這可能會像您遇到的那樣出現誤報風險這里.測試將通過這里,因為期望從未運行過.
Anything inside a then
will not be run unless the promise callbacks are called - which is a risk for a false positive like you experienced here. The test will pass here since the expect was never run.
有很多方法可以確保您不會得到這樣的誤報.例子:
There are many ways to make sure you don't get a false positive like this. Examples:
Jasmine 將等待承諾在超時內得到解決.
Jasmine will wait for the promise to be resolved within the timeout.
- 如果不及時解決,測試將失敗.
- 如果 promise 被拒絕,測試也會失敗.
當心如果您忘記返回,您的測試將給出誤報!
Beware If you forget the return, your test will give a false positive!
describe('test the returned value from the promise', function() {
return $scope.getTheData(someId)
.then(function(result) {
expect(result).toBe('something expected');
});
});
B) 使用 Jasmine 提供的 done
回調給測試方法
- 如果在超時時間內沒有調用
done
,則測試將失敗. - 如果使用參數調用
done
,則測試將失敗.
這里的catch會將錯誤傳遞給jasmine,你會看到錯誤在輸出中. - If
done
is not called within the timeout the test will fail. - If
done
is called with arguments the test will fail.
The catch here will pass the error to jasmine and you will see the error in the output.
B) Use the done
callback provided by Jasmine to the test method
當心如果您忘記了捕獲,您的錯誤將被吞沒,您的測試將因一般超時錯誤而失敗.
Beware If you forget the catch, your error will be swallowed and your test will fail with a generic timeout error.
describe('test the returned value from the promise', function(done) {
$scope.getTheData(someId)
.then(function(result) {
expect(result).toBe('something expected');
done();
})
.catch(done);
});
C) 使用間諜和手搖(同步測試)
如果你不完美,這可能是編寫測試最安全的方式.
C) Using spies and hand cranking (synchronous testing)
If you're not perfect this might be the safest way to write tests.
it('test the returned value from the promise', function() {
var
data = { data: 'lots of data' },
successSpy = jasmine.createSpy('success'),
failureSpy = jasmine.createSpy('failure');
$scope.getTheData(someId).then(successSpy, failureSpy);
$httpBackend.expect('GET', 'the/url/to/my/data').respond(200, data);
$httpBackend.flush();
expect(successSpy).toHaveBeenCalledWith(data);
expect(failureSpy).not.toHaveBeenCalled();
});
同步測試技巧
您可以在需要時手動調整 httpBackend、超時和范圍更改,以使控制器/服務更進一步.$httpBackend.flush()
, $timeout.flush()
, scope.$apply()
.
這篇關于如何使用 Jasmine 測試從 AngularJS 控制器返回的 Promise 值?的文章就介紹到這了,希望我們推薦的答案對大家有所幫助,也希望大家多多支持html5模板網!