1

我试图嘲笑角度承诺,但我遇到了一些错误,例如 undefined is not a function 评估 'spyOn' fileUploadService

我的控制器代码是

$scope.getUserFiles = function() {
    fileUploadService.retrieveUserFileNames('')
    .then(function(data) {
        $scope.userFiles =  data;
    });
};

服务代码,我从我的控制器调用这个方法

this.retrieveUserFileNames= function(userId) {
    var deferred = $q.defer();
    $http({
        method : "GET",
        url : "/retrieveExcelSheetNames",
        params : {
            "userId" : userId
        }
    }).success(function(data) {
        deferred.resolve(data);
    }).error(function(data, status) {
        deferred.reject(data);
    });
    return deferred.promise;
};

测试控制器代码

beforeEach(function() {
    inject(function(_fileUploadService_ , _$q_) {
        spyOn(scope, '$on');
        var deferred = _$q_.defer();
        fileUploadService = _fileUploadService_;
        deferred.resolve('resolveData');
        spyOn(fileUploadService, 'retrieveUserFileNames').andReturn(deferred.promise);
    });
});

it('is now a lot easier', function() {
   scope.getUserFiles();
   rootScope.$apply();
   expect(scope.userFiles).toBe('resolveData');
});

谢谢

4

1 回答 1

2

由于您$scope.userFiles在控制器中进行了异步设置,因此您需要等待解决您的承诺的$applyfrom 。$http

假设您使用 Jasmine,您可以使用异步规范符号并注册一个$watch函数来测试您的控制器(没有测试代码,因此您可能需要调整它,它还取决于范围变量的其他修改)。

it('is now a lot easier', function(done) {
  scope.$watch('userFiles', function() {
     expect(scope.userFiles).toBe('resolveData');
     // Call done function to tell Jasmine that the spec has completed
     done();
  });

  scope.getUserFiles();
});

但是,我认为您应该测试您的服务,您可以使用来自 ngMock 的 $httpBackend ,它覆盖 $http 并使您能够进行更深入的测试。在那里,您可以测试/监视对模拟后端的调用,还可以使用 Jasminesdone()函数等待承诺。

这是一个简单的例子:

angular.module('mainApp', [])
  // Simple factory that uses $http for later use of $httpBackend mocking structure
  .factory('userManager', function($http, $q) {
     return $http.get('/api/users');
  });

和规格:

describe('Simple factory that uses $http for later use of $httpBackend mocking structure', function() {
  // We need to use the module mainApp for all our tests
  beforeEach(module('mainApp'));

  // We use $httpBackend from ngMock module to mock our webservice call ($http will be overriden)
  // Also we need to inject inside of spec function as we need to use the async spec form with
  // a done function and this is not available using the inject to proxy the spec function
  it('should return desired user list', function(done) {

    inject(function($httpBackend, userManager) {

      $httpBackend.when('GET', '/api/users').respond({
        userList: [
          {user: 'User A'},
          {user: 'User B'},
          {user: 'User C'},
          {user: 'User D'},
        ]
      });
      $httpBackend.expectGET('/api/users');

      // userManager is returning a promise so we need to check asynchronously
      userManager.getUserList().then(function(result) {
        expect(result.data.userList).toContain(
          {user: 'User A'}, 
          {user: 'User B'}, 
          {user: 'User C'}, 
          {user: 'User D'}
        );

        // This call to the Jasmine done function is very important for asynchronous
        // unit tests as Jasmine is determining if the test is done by this call
        done();
      });

      $httpBackend.flush();

      $httpBackend.verifyNoOutstandingExpectation();
      $httpBackend.verifyNoOutstandingRequest();
    });
  });
});
于 2014-07-23T10:00:04.873 回答