如何在AngularJS工厂方法中模拟对象

时间:2014-07-01 20:15:22

标签: angularjs mocking angularjs-factory

我创建了一个Angular工厂,该工厂具有处理将代码保存到服务器的方法。其中一个工厂方法包含第三方对象,该对象具有执行实际标注的方法。我想测试一下这段代码,但是我无法弄清楚如何模拟第三方对象。

I have set up a plunker进行Jasmine测试。

我的目标是成功获取代码以使用我的模拟对象而不是ThirdPartySavingUtils对象。这可能吗?

var app = angular.module("MyApp", []);

app.factory("SavingUtils", function() {

  return {

    saveStuff: function() {
      if(typeof ThirdPartySavingUtils !== "undefined") {
        return ThirdPartySavingUtils.value;
      }
    }
  };
});

这是我的茉莉花测试

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 个答案:

答案 0 :(得分:1)

你真的有几个选择,但很可能你需要做两件事。

1)你可以创建一个包装这个第三方对象的角度服务 - 这样你就可以得到一个很好的抽象,你需要更改第三方对象。

2)您可以使用像http://sinonjs.org/这样的模拟框架,它可以模拟方法并像asseOnce一样执行断言。

以下是使用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));