【问题标题】:Testing Angular Service that returns a promise测试返回承诺的 Angular 服务
【发布时间】:2016-06-16 17:14:18
【问题描述】:

我使用 Karma + Jasmine 为 Angular 项目编写单元测试。

我正在尝试测试一个通过承诺返回正确结果的 Angular 服务。以下是我目前所拥有的。

项目服务

'use strict';

var app = app || {};

app.factory('ProjectSvc', ['$http', '$q', function($http, $q) {

    var project_url = 'https://dl.dropboxusercontent.com/u/2122820/hosted_json/project.json';

    var svc = {};
    svc.cachedProjects = [];

    svc.getProjects = function() {
        return $http.get(project_url);
    }

    function lookUp(slug) {
        for (var i=0; i < svc.cachedProjects.length; i++){
            if (svc.cachedProjects[i].slug && svc.cachedProjects[i].slug == slug) {
                return svc.cachedProjects[i];
            } else if (svc.cachedProjects[i].title == slug) {
                return svc.cachedProjects[i];
            
            }
        }
        return null;
    }

    //return a promise
    svc.retrieveProjectById = function(id) {
        var deferred = $q.defer();
        if (svc.cachedProjects.length > 0 ) {    
             var found = lookUp(id);
                if (!found) {
                    deferred.reject ({error: 'not found', data: null});
                } else {
                    deferred.resolve(found);
                }
        } else {
            init().then(function(data){
                //console.log('---------');
                svc.cachedProjects = data.data.projects;

                var found = lookUp(id);
                //console.log('found: ', found);
                if (!found) {
                    deferred.reject ({error: 'not found', data: null});
                } else {
                     deferred.resolve(found);
                }
            })
        }
        return deferred.promise;  
    }

     //return a promise
    svc.retrieveProjectBySlug = function(slug) {
       return svc.retrieveProjectById(slug)
    }


    function init(index) {
    	console.log('init');
        return svc.getProjects().then(function(data) {
            svc.cachedProjects = data.data.projects;
        });
    }





    return svc;



}]);

describe('Project Service', function() {
  beforeEach(module('myApp'));
  var ProjectSvc, $httpBackend;
  var $q, $rootScope;

  beforeEach(inject(function(_ProjectSvc_, _$httpBackend_, _$q_, _$rootScope_) {
    // The injector unwraps the underscores (_) from around the parameter names when matching
    ProjectSvc = _ProjectSvc_;
    $httpBackend = _$httpBackend_;
    $q = _$q_;

    $rootScope = _$rootScope_;

    spyOn(ProjectSvc, 'retrieveProjectBySlug').and.callFake(function() {
      var defer = $q.defer();
      defer.resolve();
      return defer.promise;
    });
  }));


  describe('.retrieveProjectBySlug()', function() {
    it('test promise in service', function() {

      var project_url = 'https://dl.dropboxusercontent.com/u/2122820/hosted_json/project.json';
      //$httpBackend.expectGET(project_url).respond(200, {data: null});

      console.log('-------------');
      var project;
      ProjectSvc.retrieveProjectBySlug('monopoly-checker').then(function(data) {
        project = data;
        console.log(project);
        $rootScope.$apply();
        console.log('project', project);

      });

      expect(project.length).toBe(1);
    });
  });
});
http://stackoverflow.com/questions/ask#

运行karma start,我明白了:

1) test promise in service
 Project Service .retrieveProjectBySlug()
 TypeError: Cannot read property 'length' of undefined

似乎承诺永远不会得到解决,因此project 始终未定义。你能解决这个问题吗?

如果有帮助,完整的源代码在https://github.com/rattanakchea/rattanakchea.github.io/tree/test

【问题讨论】:

  • 你的期望在 promise 被解决之前运行,因此它是未定义的?

标签: angularjs testing jasmine karma-runner


【解决方案1】:

$rootScope.$apply() 应该在 Promise 之外调用:

  ProjectSvc.retrieveProjectBySlug('monopoly-checker').then(function(data) {
    project = data;
    console.log(project);
    console.log('project', project);
  });

  $rootScope.$apply();

$qpromise 绑定到摘要循环,promise 链在摘要上调用。

考虑使用 Jasmine promise matchers,它们消除了在规范中解开 $q 承诺的需要。

【讨论】:

  • 我按照你的建议做了,并在测试中得到了这个:1) test promise in service Project Service .retrieveProjectBySlug() TypeError: Cannot read property 'length' of undefined
  • 承诺本身已经过测试,就像答案中显示的那样。 defer.resolve() 解析为 undefined,因此它是未定义的。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-06-17
  • 2014-05-19
  • 2017-02-21
  • 2013-06-29
  • 1970-01-01
  • 2015-12-02
  • 2015-05-29
相关资源
最近更新 更多