1

angular promise をモックしようとしましたが、 undefined is not a function Evaluation '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

コントローラーで非同期に設定されているため、promise が解決されるまで$scope.userFiles待つ必要があります。$apply$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 に答える