Как издеваться над объектом в фабричном методе AngularJS

#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 смотрите правку — действительно рад видеть, что вы думаете о тестировании!