【问题标题】:Unit test an angular controller and service which uses a promise?单元测试使用承诺的角度控制器和服务?
【发布时间】:2017-02-27 21:16:06
【问题描述】:

我无法让测试结果通过我正在使用一个非常基本的实现来更深入地了解测试。

我有一个工厂,它返回一个承诺,从我的控制器访问。我想测试调用是否成功并将响应分配给repos var。以下是代码:

'use strict';

angular.module('app')
  .factory('searchServ', function ($timeout, $q, $http) {
    return {
      fetch: function(user) {
        var deferred = $q.defer();

        $timeout(function(){
          $http({method: 'GET', url: 'https://api.github.com/users/' + user + '/repos'}).then(function(repos) {
            deferred.resolve(repos.data);
          }, function(reason){
            deferred.reject(reason.status);
            console.log(reason);
          });
        }, 30);

        return deferred.promise;
      }
    };
  })
  .controller('MainCtrl', function ($scope, searchServ) {
    $scope.results = function(user) {
      $scope.message = '';
      searchServ.fetch(user).then(function (repos) {
        if(repos.length){
          $scope.message = '';
          $scope.repos = repos;
        }
        else{
          $scope.message = 'not found'
        }
      }, function (){
        $scope.message = 'not found';
      });
    };
  });

//Test

'use strict';

describe('MainCtrl', function () {
  var scope, searchServ, controller, deferred, repos = [{name: 'test'}];
  // load the controller's module
  beforeEach(module('app'));

  beforeEach(inject(function($controller, $rootScope, $q) {
    searchServ = {
      fetch: function () {
        deferred = $q.defer();
        return deferred.promise;
      }
    };
    spyOn(searchServ, 'fetch').andCallThrough();
    scope = $rootScope.$new();
    controller = $controller('MainCtrl', {
      $scope: scope,
      fetchGithub: fetchGithub
    });


  }));
  it('should test', function () {
    expect(scope.test).toEqual('ha');
  });

  it('should bind to scope', function () {
    scope.results();
    scope.$digest();
    expect(scope.message).toEqual('');
    //expect(scope.repos).not.toBe(undefined);
  });
});

运行测试给我以下错误:

TypeError: undefined is not a function (evaluating 'spyOn(searchServ, 'fetch').andCallThrough()') in test/spec/controllers/main.js (line 15)

知道如何测试它以测试范围绑定以及异步调用吗?

【问题讨论】:

  • 没有andCallThrough。它是and.callThrough。您广泛使用deferred antipattern。在你的情况下结果会很糟糕。因为 searchServ.fetch 在您的情况下返回未解决的承诺。
  • 我已经尝试过 and.callThrough 但它总是返回未定义,我也在尝试另一种方法,比如这个小提琴jsfiddle.net/upoc0ott/2 但仍然未定义,如果有人可以帮助我使用,那就太棒了无论哪种方式?

标签: angularjs unit-testing asynchronous jasmine karma-jasmine


【解决方案1】:

你的代码有很多问题。

我为此创建了 this Plunkrindex.js 是包含您的代码和测试用例的文件。我根据约定和最佳实践编辑了大部分部分。

我想给你一些建议:

  • 由于$http 返回一个promise,您应该使用它,而不是解决promise 并从您的方法创建另一个promise。不知道为什么使用超时。所以我从searchServ 的依赖项中删除了$q$timeout
  • 我在测试用例中做了同样的事情,删除了您使用的 deferred 变量。
  • 您应该使用angular-mocks.js 来模拟您的服务和其他依赖项,而不是在您的测试用例中定义一个服务(就像您所做的那样。)
  • 您应该创建单独的 describe 块来测试代码的不同部分(在本例中为 controller)。

希望这会有所帮助!

【讨论】:

  • 这是一个绝妙的答案!非常感谢您抽出宝贵的时间。我使用了 $timeout 和 $q 因为它们是基于承诺的调用,如果您通过 yeoman 生成工厂/服务,它将为您提供这种方法,但由于 $http 也返回一个承诺,我认为它同样有效! :)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-03-15
  • 1970-01-01
  • 2017-10-09
  • 1970-01-01
  • 2016-07-25
  • 1970-01-01
相关资源
最近更新 更多