У меня есть myService
то , что использует myOtherService
, что делает удаленный вызов, возвращая обещание:
angular.module('app.myService', ['app.myOtherService'])
.factory('myService', [
myOtherService,
function(myOtherService) {
function makeRemoteCall() {
return myOtherService.makeRemoteCallReturningPromise();
}
return {
makeRemoteCall: makeRemoteCall
};
}
])
Чтобы выполнить юнит-тест для myService
меня, мне нужно смоделировать myOtherService
, чтобы его makeRemoteCallReturningPromise
метод возвращал обещание. Вот как я это делаю:
describe('Testing remote call returning promise', function() {
var myService;
var myOtherServiceMock = {};
beforeEach(module('app.myService'));
// I have to inject mock when calling module(),
// and module() should come before any inject()
beforeEach(module(function ($provide) {
$provide.value('myOtherService', myOtherServiceMock);
}));
// However, in order to properly construct my mock
// I need $q, which can give me a promise
beforeEach(inject(function(_myService_, $q){
myService = _myService_;
myOtherServiceMock = {
makeRemoteCallReturningPromise: function() {
var deferred = $q.defer();
deferred.resolve('Remote call result');
return deferred.promise;
}
};
}
// Here the value of myOtherServiceMock is not
// updated, and it is still {}
it('can do remote call', inject(function() {
myService.makeRemoteCall() // Error: makeRemoteCall() is not defined on {}
.then(function() {
console.log('Success');
});
}));
Как видно из вышесказанного, определение моего макета зависит от того $q
, что я должен загрузить, используя inject()
. Кроме того, инъекция должна происходить в том месте module()
, которое должно быть раньше inject()
. Однако значение для макета не обновляется, как только я его изменяю.
Как правильно это сделать?
javascript
angularjs
unit-testing
mocking
jasmine
Георгий Олейников
источник
источник
myService.makeRemoteCall()
? Если так, то проблема вmyService
томmakeRemoteCall
, что вы не имеете ничего общего с вашим издевательствомmyOtherService
.Ответы:
Я не уверен, почему то, как ты это сделал, не работает, но я обычно делаю это с помощью
spyOn
функции. Что-то вроде этого:Также помните, что вам нужно будет
$digest
вызватьthen
функцию для вызова . Смотрите раздел Тестирование документации $ q .------РЕДАКТИРОВАТЬ------
Посмотрев ближе на то, что вы делаете, я думаю, что вижу проблему в вашем коде. В
beforeEach
, вы устанавливаетеmyOtherServiceMock
совершенно новый объект.$provide
Никогда не увидит эту ссылку. Вам просто нужно обновить существующую ссылку:источник
andCallFake
тебя можно использоватьandReturnValue(deferred.promise)
(илиand.returnValue(deferred.promise)
в Жасмин 2.0+). Вы должны определить,deferred
прежде чем позвонитьspyOn
, конечно.$digest
в этом случае, когда у вас нет доступа к области?$rootScope
и вызываете$digest
это.$q.when()
codelord.net/2015/09/24/$q-dot-defer-youre-doing-it-wrongМы также можем написать реализацию возвращаемого обещания Жасмин непосредственно шпионом.
Для Жасмин 2:
(скопировано из комментариев, спасибо ccnokes)
источник
spyOn(myOtherService, "makeRemoteCallReturningPromise").and.returnValue($q.when({}));
я просто убил полчаса, чтобы понять это.источник
Вы можете использовать библиотеку-заглушку, такую как sinon, чтобы высмеивать ваш сервис. Затем вы можете вернуть $ q.when () как ваше обещание. Если значение вашего объекта области видимости исходит из результата обещания, вам нужно будет вызвать область действия. $ Root. $ Digest ().
источник
$rootScope.$digest()
получить обещание, которое будет решеноиспользуя
sinon
:Известно, что
httpPromise
можно:источник
Честно говоря ... вы делаете это неправильно, полагаясь на инъекцию, чтобы смоделировать сервис вместо модуля. Кроме того, вызов inject в beforeEach является анти-паттерном, поскольку он затрудняет mocking для каждого теста.
Вот как бы я это сделал ...
Теперь, когда вы вводите свой сервис, у него будет правильно смоделированный метод для использования.
источник
Я нашел эту полезную сервисную функцию с режущим заголовком как sinon.stub (). Return ($ q.when ({})):
контроллер:
и проверить
источник
Фрагмент кода:
Можно записать в более сжатой форме:
источник