#angularjs #mocking #angularjs-factory
#angularjs #издевательство #angularjs-factory
Вопрос:
Я создал Angular factory, в котором есть методы, которые обрабатывают сохранение кода на сервере. Один из заводских методов содержит сторонний объект, у которого есть метод, который выполняет фактическую выноску. Я хотел бы протестировать этот код, но я не могу понять, как издеваться над сторонним объектом.
Я настроил плунжер с тестом Jasmine.
Моя цель этого теста — просто успешно заставить код использовать мой макет объекта, а не объект ThirdPartySavingUtils. Возможно ли это?
var app = angular.module("MyApp", []);
app.factory("SavingUtils", function() {
return {
saveStuff: function() {
if(typeof ThirdPartySavingUtils !== "undefined") {
return ThirdPartySavingUtils.value;
}
}
};
});
это мои тесты jasmine
describe("Mocking Test", function() {
var ThirdPartySavingUtilsMock;
var SavingUtils;
beforeEach(function() {
angular.mock.module("MyApp", function($provide) {
ThirdPartySavingUtilsMock = {
value: "I am the mock object"
};
$provide.value("ThirdPartySavingUtils", ThirdPartySavingUtilsMock);
});
inject(function(_SavingUtils_) {
SavingUtils = _SavingUtils_;
});
});
it("should run without throwing an exception", function() {
expect(true).toBe(true);
});
it("should mock out ThirdPartySavingUtils with ThirdPartySavingUtilsMock", function() {
var result = SavingUtils.saveStuff();
expect(result).toEqual("I am the mock object");
});
});
Ответ №1:
На самом деле у вас есть несколько вариантов, но, скорее всего, вам нужно будет сделать оба.
1) Вы могли бы создать службу angular, которая оборачивает этот сторонний объект — таким образом, вы получаете хорошую абстракцию на случай, если вам когда-нибудь понадобится изменить сторонний объект.
2) Вы могли бы использовать издевательский фреймворк, такой какhttp://sinonjs.org / которые позволяют вам издеваться над методами и выполнять утверждения, такие как calledOnce и т.д.
Вот ссылка на издевательский тест с использованием sinon test.
В основном вы можете видеть, что sinon используется в качестве изолированной среды для макетирования методов объекта. Sinon предоставляет дополнительные свойства для этих издеваемых методов, чтобы вы могли утверждать, были ли они вызваны, параметры, которые они вызывали, даже с порядком вызовов. Это действительно, действительно важный инструмент тестирования.
describe('validationManager', function () {
beforeEach(inject(function ($injector) {
sandbox = sinon.sandbox.create();
$rootScope = $injector.get('$rootScope');
$compile = $injector.get('$compile');
$q = $injector.get('$q');
defer = $q.defer();
validator = $injector.get('validator');
validationManager = $injector.get('validationManager');
sandbox.stub(validator, 'makeValid');
sandbox.stub(validator, 'makeInvalid');
sandbox.stub(validator, 'getErrorMessage').returns(defer.promise);
setModelCtrl();
}));
afterEach(function () {
sandbox.restore();
setModelCtrl();
});
it('should be defined', function () {
expect(validationManager).to.exist;
});
describe('validateElement', function () {
it('should return if no $parsers or $formatters on the controller', function () {
validationManager.validateElement(modelCtrl);
expect(validator.makeValid.called).to.equal(false);
expect(validator.makeInvalid.called).to.equal(false);
});
});
Редактировать ————————
Здесь это применяется на практике для вашего кода (я не запускал это, но это дает общую идею).
(function (angular, ThirdPartyApi) {
'use strict';
var app = angular.module('MyApp', []);
app.factory('thirdPartApi', [
function () {
return {
save: ThirdPartyApi.save,
value: ThirdPartyApi.value
};
}
]);
app.factory('SavingUtils', [
'thirdPartApi',
function (thirdPartApi) {
var getValue = function () {
return thirdPartApi.value;
},
save = function (item) {
return thirdPartApi.save(item);
};
return {
save: save,
getValue: getValue
};
}
]);
}(angular, window.ThirdPartyApi));
Тесты…..
(function (angular, sinon) {
'use strict';
describe('MyApp.SavingUtils', function () {
var sandbox, thirdPartyApi, SavingUtils, thirdPartyApiValue = 2;
beforeEach(inject(function ($injector) {
sandbox = sinon.sandbox.create();
thirdPartyApi = $injector.get('thirdPartyApi');
SavingUtils = $injector.get('SavingUtils');
// stub the method and when called return a simple object or whatever you want
sandbox.stub(thirdPartyApi, 'save').returns({ id: 1});
sandbox.stub(thirdPartyApi, 'value', function () {
return thirdPartyApiValue;
});
}));
afterEach(function () {
// This removes those stubs and replace the original methods/values
sandbox.restore();
});
describe('save', function () {
it('should return call the save method on thirdPartyApi', function () {
var item = {};
SavingUtils.save(item);
expect(thirdPartyApi.save.calledOnce).to.equal(true);
});
});
describe('getValue', function () {
it('should return value of value property on thirdPartyApi', function () {
var result = SavingUtils.getValue();
expect(result).to.equal(thirdPartyApiValue);
});
});
});
}(angular, sinon));
Комментарии:
1. Спасибо за ваш ответ и пример кода. Мне нужно будет взглянуть на Sinon и попробовать обернуть сторонний код сервисом. Не могли бы вы сказать мне, что было не так с тем, как я пытался это сделать? Возможно ли издеваться над этим объектом так, как я пытаюсь это сделать? Спасибо
2. @Joe смотрите правку — действительно рад видеть, что вы думаете о тестировании!