AngularJS promise 在使用 Jasmine 进行测试时不会调用 then

标签 angularjs jasmine

当我尝试测试使用 jasmine promise 的 Controller 时,我遇到了一些问题。

我有以下 Jasmine 测试:

describe('Testing a controller', function () {
    var $scope, $root, ctrl, $q, deferred;
    var MockService;

    beforeEach(function () {
        module('myApp');
        inject(function ($rootScope, $controller, $q) {

            $root = $rootScope;
            $scope = $rootScope.$new();

            MockService = {
                fetch: function () {
                    return {
                        get: function () {
                            deferred = $q.defer();
                            return {
                                $promise: deferred.promise
                            };
                        }
                    };
                }
            };

            ctrl = $controller('myController', {
                $scope: $scope,
                $root: $rootScope,
                MyService: MockService,
            });
        });

        spyOn(MockService, 'fetch').andCallThrough();
    });

    it('Get data from promise', function () {

        $scope.init();
        deferred.resolve("It worked!");
        $root.$digest();
        expect(MockService.fetch).toHaveBeenCalled();
        expect($scope.test).toBe('It worked!');
    });

});

这是 Controller :

controllers.controller('myController', ['$scope','MyService'
    function ($scope, myService) {
        $scope.init = function () {
            myService.fetch().get().$promise.then(function (data) {
                $scope.test = data;
            }, function (error) {
                $scope.error = error;
            });
        };
    }
]);

测试一直失败:“预期未定义为‘It Worked!’。”

看起来 promise 得到了解决,并且“then”函数从未被调用。有什么想法吗?

最佳答案

您上面提供的代码似乎可以工作(现在 @dfsq 的修复已应用)。

我只能通过注释掉以下任一行来重现您遇到的错误:

deferred.resolve("It worked!");
$root.$digest();

...这让我想知道在您的实际代码(不是上面提供的示例)中,上述两行代码的等效项的实现是否存在问题。

您是否曾在同一测试的早期阶段执行过 deferred.reject()deferred.resolve() 而不传递参数?

使用 HTMLReporter 进行 jasmine 测试的演示:

/* Angular App */
(function() {
  "use strict";
  angular.module('myApp', [])
    .controller('myController', ['$scope', 'MyService',
      function($scope, myService) {
        $scope.init = function() {
          myService.fetch().get().$promise.then(function(data) {
            $scope.test = data;
          }, function(error) {
            $scope.error = error;
          });
        };
      }
    ]);
})();

/* Unit Test */
(function() {
  "use strict";
  var consoleLog = document.querySelector('#log');

  describe('Testing a controller', function() {
    var $scope, $root, ctrl, $q, deferred;
    var MockService;

    beforeEach(function() {
      module('myApp');
      inject(function($rootScope, $controller, $q) {

        $root = $rootScope;
        $scope = $rootScope.$new();

        MockService = {
          fetch: function() {
            return {
              get: function() {
                deferred = $q.defer();
                return {
                  $promise: deferred.promise
                };
              }
            };
          }
        };

        ctrl = $controller('myController', {
          $scope: $scope,
          $root: $rootScope,
          MyService: MockService,
        });
      });

      spyOn(MockService, 'fetch').andCallThrough();
    });

    it('Get data from promise', function() {
      consoleLog.innerHTML += "<p>" + [
        "START OF TEST:",
        "$scope.test: " + $scope.test,
        "$scope.error: " + $scope.error
      ].join("<br />") + "</p>";

      $scope.init();
      deferred.resolve("It worked!");
      $root.$digest();
      expect(MockService.fetch).toHaveBeenCalled();
      expect($scope.test).toBe('It worked!');

      consoleLog.innerHTML += "<p>" + [
        "END OF TEST:",
        "$scope.test: " + $scope.test,
        "$scope.error: " + $scope.error
      ].join("<br />") + "</p>";
    });

  });
})();


/* Jasmine Bootstrap */
(function() {
  "use strict";

  var jasmineEnv = jasmine.getEnv(),
    htmlReporter = new jasmine.HtmlReporter();

  jasmineEnv.addReporter(htmlReporter);
  jasmineEnv.execute();

})();
<link rel="stylesheet" href="//cdn.jsdelivr.net/jasmine/1.3.1/jasmine.css" />
<script src="//cdn.jsdelivr.net/jasmine/1.3.1/jasmine.js"></script>
<script src="//cdn.jsdelivr.net/jasmine/1.3.1/jasmine-html.js"></script>
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.2.28/angular.min.js"></script>
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.2.28/angular-mocks.js"></script>

<pre id="log"></pre>

关于AngularJS promise 在使用 Jasmine 进行测试时不会调用 then,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32114595/

相关文章:

javascript - 为什么指令模板有时从服务器加载(带有 304 响应),有时从浏览器缓存加载(根本没有请求)?

javascript - JSON.parse 不会将 JSON 字符串转换为 Angular 中的对象

javascript - Karma + ui-router 失败 : Cannot read property 'isDefined' of undefined

javascript - 单元测试 AngularJS 模块 Controller

javascript - 如何使变量表现为对象?

javascript - 如何使用 angular 1.0.8 在 ng repeat 中使用 if 语句

javascript - 无法将数组加载到 ngTable

javascript - angularjs $resouce 方法中的可选参数

Angular 使用 Karma 和 Jasmine TypeError : this. Service.<foo> 不是 Lifecycle Hook 中的函数

javascript - Protractor ElementFinder/ElementArrayFinder 理解