2016-08-31 12 views
5

私はAngularの新機能を使用しており、一連の呼び出しをRESTサービスにラップするAPIレベルのサービスを実行するAngularサービスをテストするよう努めています。 HTTPリクエストを処理しているので、サービスの両方の部分が約束どおりに動作していますが、正常に動作しているように見えますが、約束された動作をテストするのに問題があります。Angularサービスのジャスミンテストで延期されたコールが解決されない

は私のサービスコード(著しく単純化された)の関連部分は次のようになります。

describe("Info Service ", 
    function() { 
     var infoService, infoRequestApi, $q; 
     beforeEach(module("my.info")); 
     beforeEach(function() { 
      module(function($provide) { 
       infoRequestApi = { 
        requestCount: 0, 
        getAllInfo: function() { 
         var defer = $q.defer(); 
         this.requestCount++; 
         defer.resolve([ "info 1", "info 2" ]); 
         return defer.promise; 
        } 
       }; 
       $provide.value("infoApi", infoRequestApi); 
      }); 
      inject(function(_myInfoService_, _$q_) { 
       infoService = _myInfoService_, 
       $q = _$q_; 
      }); 
     }); 

     it("should not fail in the middle of a test", function(done) { 
      infoService.getInfo().then(function(infoResult) { 
        // expectation checks. 
        expect(true).toBeTrue(); 
       }).finally(done); 
     }); 
    }); 

どれ同期のテストに合格:私は私のモックを設定していた場合

angular.module('my.info') 
.service('myInfoService', function (infoApi, $q) { 
    infoLoaded: false, 
    allInfo: [], 
    getInfo: function() { 
     var defer = $q.defer(); 
     if (infoLoaded) { 
      defer.resolve(allInfo); 
     } else { 
      infoApi.getAllInfo().then(function (newInfo) { 
       allInfo = newInfo; 
       infoLoaded = true; 
       defer.resolve(allInfo); 
      }); 
     } 
     return defer.promise; 
    } 
}); 

私はこのような何かを持っていますこのようなテストを実行しようとすると、次のようなメッセージが表示されます。Error: Timeout - Async callback was not invoked within timeout specified by jasmine.DEFAULT_TIMEOUT_INTERVAL.

Angular.Moc ksが遅延結果を処理して失敗する。テストをステップ実行すると、mockオブジェクトのdefer変数が正しく設定されていますが、サービス内のthen文は呼び出されません。どこが間違っていますか?

答えて

3

短い答え

あなたはダイジェストサイクルをキックオフする必要があります。あなたは$rootScope.$apply()でそれを行うことができます。

it("should not fail in the middle of a test", inject(function($rootScope) { 
    var actualResult = null; 
    infoService.getInfo() 
    .then(function(infoResult) { actualResult = infoResult; }); 
    $rootScope.$apply(); 
    expect(actualResult).toEqual(["info 1", "info 2"]); 
})); 

私は偽物infoRequestApiサービスにあなたがそれをやっている方法を作成しようとしないでしょう。あなたはそのサービスを注入し、その機能を偵察するべきです。例えば、このような何か:

it("should not fail in the middle of a test", inject(function($rootScope, infoApi, $q) { 
    var deferred = $q.defer(); 
    spyOn(infoApi, 'getAllInfo').and.returnValue(deferred.promise); 
    var actualResult = null; 
    var expectedResult = ["info 1", "info 2"]; 

    infoService.getInfo() 
    .then(function(infoResult) { actualResult = infoResult; }); 

    deferred.resolve(expectedResult); 
    $rootScope.$apply(); 
    expect(actualResult).toBe(expectedResult); 
})); 

をリファクタリングまた、あなたのコードを簡素化することができるビット(テストされていないが、私はを見ることを期待するものに近いです)。

angular.module('my.info') 
    .service('myInfoService', function (infoApi, $q) { 
    return { 
     infoLoaded: false, 
     allInfo: [], 
     getInfo: function() { 
     var self = this; 
     return this.infoLoaded ? $q.resolve(this.allInfo) : 
      infoApi.getAllInfo().then(function (newInfo) { 
      self.allInfo = newInfo; 
      self.infoLoaded = true; 
      }); 
    } 
    }; 
}); 

describe("Info Service ", function() { 
    var infoService, infoApi, $q, $rootScope; 

    beforeEach(module("my.info")); 
    beforeEach(inject(function(_myInfoService_, _$q_ _$rootScope_, _infoApi_) { 
    infoService = _myInfoService_, 
    $q = _$q_; 
    $rootScope = _$rootScope_; 
    infoApi = _infoApi_; 
    }); 

    it("should do something", function() { // update message 
    var deferred = $q.defer(); 
    spyOn(infoApi, 'getAllInfo').and.returnValue(deferred.promise); 
    var actualResult = null; 
    var expectedResult = ["info 1", "info 2"]; 

    infoService.getInfo() 
     .then(function(infoResult) { actualResult = infoResult; }); 

    deferred.resolve(expectedResult); 
    $rootScope.$apply(); 
    expect(actualResult).toBe(expectedResult); 
    }); 
}); 
+0

丁寧に回答いただきありがとうございました。私は嘲笑のアプローチが少し長めだったと思った!私が今抱えている唯一の問題は、いくつかのサービス層を持っていて、すべてのコンストラクタのモックを途中まで挿入する必要があるように見えているようですが、これははるかに精巧でより慣用的です。 – glenatron

+0

@glenatron問題ありません。テスト対象のサービスで使用されている依存関係を模擬する必要があります。依存関係を模倣する必要はないので、レイヤの問題は疑問です。 –

+0

あなたは正しいですが、私は実際には偽の失敗を引き起こしていたVisual StudioのChutzpahテストランナーに問題が発生していました。同じテストは、他のテストランナーの下でうまく動作します。 – glenatron

関連する問題