使用SinonJs模拟Angular存储库

时间:2014-07-15 23:40:05

标签: angularjs mocking jasmine sinon

我对Angular \ SinonJS有点新意,所以请原谅这个愚蠢的问题,如果这很明显就要忍受。我做了一些谷歌搜索,似乎无法找到答案。我已经使用SinonJs进行模拟,因为这是在Pluralsight视频中推荐的。不确定它是否是最佳选择。任何替代方案都欢迎。

我想测试我的AngularJS控制器的行为,并测试它使用我指定的标准调用我的存储库搜索方法一次。

我的控制器中有以下内容,并且在我的Jasmin测试运行器中出现错误:

目标controller.js:

stepByStepApp.controller("goalController", function ($scope, goalRepository) {

    $scope.viewGoalButtonDisabled = true;

    $scope.search = function (criteria) {
        $scope.errors = [];
        return goalRepository.search(criteria).$promise.then(
            function (goals) {
                $scope.viewGoalButtonDisabled = true;
                return goals;
            },
            function (response) {
                $scope.viewGoalButtonDisabled = true;
                $scope.errors = response.data;
            });
    };

});

目标控制器-tests.js

'use strict';

(function () {
    describe('Given a Goal Controller', function () {
        var scope, controller, goalRepositoryMock, goals, criteria;

        beforeEach(function () {
            module('stepByStepApp');

            inject(function ($rootScope, $controller, goalRepository) {
                scope = $rootScope.$new();
                goalRepositoryMock = sinon.mock(goalRepository);

                goals = [{ foo: 'bar' }];
                criteria = 'test search criteria';

                controller = $controller('goalController', { $scope: scope });
            });
        });

        it('the View Goal Button should be disabled', function () {
            expect(scope.viewGoalButtonDisabled).toBe(true);
        });

        describe("when a goal is searched for, it", function () {

            it("should search the Goal Repository", function () {
                goalRepositoryMock.expects('search').once().returns(goals);

                scope.search(criteria);

                goalRepositoryMock.verify();
            });
        });
    });
}())

我收到以下错误:

2 specs, 1 failure 
Given a Goal Controller
    when a goal is searched for, it
        should search the Goal Repository 
        TypeError: Cannot read property 'then' of undefined

我显然没有嘲笑对" goalRepository.search(条件)的调用。$ promise.then"正常。我如何正确地模仿$ promise和.then?提前谢谢。

1 个答案:

答案 0 :(得分:2)

我假设此存储库正在返回资源对象。话虽如此,这是我将如何测试这个控制器。

这是工作plunk

在每个块之前的初始值

你需要嘲笑承诺链。为此,您需要注入$ q服务。以下是我的课前广泛的声明。我使用存根进行模拟。我将那个模拟注入我测试的控制器中。

beforeEach(inject(function($controller, $rootScope, $q) {

   q = $q

   scope = $rootScope;

   goalRepositoryStub = sinon.stub({
     search: function() {}
   });

   testCtrl = $controller("goalController", {
     $scope: scope,
     goalRepository: goalRepositoryStub
   });
}));

通过这个模拟的存储库,我现在可以完全控制它的功能。

beforeEach for test repo

在这个区块中,我实际上模拟了整个承诺链。我从q服务中得到一个推迟的对象。从中我得到了承诺。然后我把这个承诺放在一个假的资源对象中。然后,每当调用搜索时,我都会返回该伪资源对象。然后我在范围内调用搜索。

beforeEach(function() {
  deferred = q.defer();
  promise = deferred.promise;
  returnedResource = {
    $promise: promise
  };


  goalRepositoryStub.search.returns(returnedResource);
  scope.search(criteria);
});

实际测试

对于实际测试,您需要告诉延迟对象要做什么(拒绝或解析promise)并触发范围$ apply()函数。然后,您将测试您的代码是否正在执行它应该执行的操作。

以下是我如何测试对goalRepository的成功调用的示例:

describe('successful goalRepository call', function() {
  beforeEach(function() {
    deferred.resolve(dataToReturn);
    scope.$apply();
  });

  it('should add the data to scope.goals.', function() {
    expect(scope.goals).toBe(dataToReturn);
  });

  it('should not change scope.failureApi to true.', function() {
    expect(scope.viewGoalButtonDisabled).toBeFalsy();
  });
});

这些不是必要的“最佳实践”或任何其他内容。只是我发现自己解决这个问题的方法。