2016-02-16 31 views
22

私はジャスミンで私のアプリをテストしようとして、次の問題があります:
私は約束のthenの関数を計算します。それが私のコードをテストする必要があるポイントです。ここで ジャスミンテストpromise.then関数

は私のコントローラのコードです:

TestCtrl.$inject = ["$scope", "TestService"]; 
    /* ngInject */ 
    function TestCtrl($scope, TestService) { 
    $scope.loadData = function() { 
     TestService.getData().then(function (response) { 
     $scope.data = response.data; 
     $scope.filtered = $scope.data.filter(function(item){ 
      if(item.id > 1000){ 
      return true; 
      } 
      return false; 
     }) 
     }); 
    } 
    } 

そして、私のジャスミンのテストコード:

describe('TestService tests', function() { 
    var $q; 
    beforeEach(function() { 
    module('pilot.fw.user'); 
    }); 
    beforeEach(inject(function (_$q_) { 
    $q = _$q_; 
    })); 
    describe('UserController Tests', function() { 

    beforeEach(inject(function (_$httpBackend_, $rootScope, $controller) { 
     this.scope = $rootScope.$new(); 
     this.$rootscope = $rootScope; 
     this.$httpBackend = _$httpBackend_; 
     this.scope = $rootScope.$new(); 
     var TestServiceMock = { 
     getData: function() { 
      var deferred = $q.defer(); 
      var result = [{ 
      "id": 1720, 
      "user": 1132 
      }, 
      { 
       "id": 720, 
       "user": 132 
      }, { 
       "id": 1721, 
       "user": 1132 
      }]; 
      deferred.promise.data = result; 
      deferred.resolve(result); 
      return deferred.promise; 
     } 
     }; 
     this.controller = $controller('TestCtrl', { 
     '$scope': this.scope, 
     'TestService': TestServiceMock 
     }); 
    })); 

    it('test', function(){ 
     this.scope.loadData(); 
     expect(true).toBeTruthy(); 
    }) 
    }); 
}); 

私は理解していない奇妙なことは、(コンソールログでテストされる):

  • 私の約束が作成され返されました
  • 私のloadData fu nctionは私が解決

としての約束を返すものの、その後、関数内すべてが、どのように私は、内のコードをテストすることができ、実行されることはありませんと呼ばれ、それがTestService

  • からのgetData()関数を呼び出します機能?ジャスミン「は」メソッドは、あなただけのときに行わ呼び出してください、あなたが好きな深い行くこと自由に感じ

    it('Should be async', function(done) { 
        someAsyncFunction().then(function(result) { 
        expect(result).toBe(true); 
        done(); 
        }); 
    }); 
    

    非同期テストのために呼び出すことができます行わパラメータを取る助け

  • 答えて

    29

    ため
    感謝すべてが終わった。 Jasmineのデフォルトのタイムアウトはテストごとに5秒です。したがって、非同期の処理が完了していない場合、ジャスミンがクラッシュします。 configsでこの設定を変更するか、ターミナルで設定することができます。

    これは、私はそれが10秒で動作しない場合は、障害のあるメソッドを持っていることと思いデフォルトのタイムアウト間隔

    describe("long asynchronous specs", function() { 
        var originalTimeout; 
        beforeEach(function() { 
        originalTimeout = jasmine.DEFAULT_TIMEOUT_INTERVAL; 
        jasmine.DEFAULT_TIMEOUT_INTERVAL = 10000; 
        }); 
    
        it("takes a long time", function(done) { 
        setTimeout(function() { 
         done(); 
        }, 9000); 
        }); 
    
        afterEach(function() { 
        jasmine.DEFAULT_TIMEOUT_INTERVAL = originalTimeout; 
        }); 
    }); 
    

    を処理する方法をあなたに示し、ジャスミンのドキュメントからまっすぐです。特に、ローカルサーバー/ dbと通信している場合は特にそうです。あなたは重い計算を実行している場合、またはそれほど素晴らしいインターネット接続で外部APIを打っている場合、このようなものはこの時間がかかるだけです。すべてがローカルの場合(またはスタブされている/嘲笑されている場合)、5-10秒を超えるものは明確な赤旗です。

    +0

    それ( 'テスト'、関数(行う){ TestServiceMock.getData()を(関数(結果){ にconsole.log(結果); }); )((真).toBeTruthyを期待。 )(完了; }) 私はこのようにそれを試してみましたが、私のコンソールは以前とさえ呼ばれる... 同じ問題isn'tログ:/ - 編集が終わっを呼んでいる –

    +0

    あなたの助けを タンク - CodeStyleのため申し訳ありませんが「その時」の外側に! 「完了」がメソッドの中にあることを確認してください:) –

    +0

    それ以外の場合は、約束が解決される前に実行しています。私の例では、約束の結果をexpectメソッドに渡す方法に注目してください。これは、 'then'の内部にある解決されたときにのみ機能します –

    0

    あなたのコントローラーに関しては、値を「返す」必要があります。

    TestCtrl.$inject = ["$scope", "TestService"]; 
    /* ngInject */ 
    function TestCtrl($scope, TestService) { 
        $scope.loadData = function() { 
        // Return this call, since it will return a new promise 
        // This is what let's you do $scope.loadData.then() 
        return TestService.getData().then(function (response) { 
         // What you return in here will be the first argument 
         // of your then method, in the tests/any env 
         // Ex. return 'foo' 
         // will result in .then(result => result === 'foo') //=> true 
         // return one of these, i suggest the data, go SRP! 
         return $scope.data = response.data; 
    
         // I would do this stuff in a separate function, but you 
         // can return 'filtered' instead if you like. 
         // 
         // $scope.filtered = $scope.data.filter(function(item){ 
         // if(item.id > 1000){ 
         //  return true; 
         // } 
         // return false; 
         // }); 
        }); 
        } 
    } 
    

    の後に何かを呼び出す「し、」何も意味しない、値が「し、」INSIDE呼ばれなければならないことに注意してください。それの後、またはそれの前に。しかし、それの中に。トム・グリーンのように、フレディーの貧弱なムースが手に取った。

    +0

    ラフ、私はFGFの参照をupvoteしたいと思うが、彼らはビューのために何かを返さない限り、コントローラが何かを返すとは思わない。 –

    1

    Angular 1.xと2.x +プロジェクトで私が何をしているか教えてください。角度テストツールを使用して、非同期テストでコールバック/ネストを取り除くことができます。角度1.xでは、$ qと$ rootScope。$ apply()の組み合わせを使用することを意味します。角度2.x +では、fakeAsyncのようなものを使用することを意味します。

    From the Angular 1.x docs

    it('should simulate promise', inject(function($q, $rootScope) { 
        var deferred = $q.defer(); 
        var promise = deferred.promise; 
        var resolvedValue; 
    
        promise.then(function(value) { resolvedValue = value; }); 
        expect(resolvedValue).toBeUndefined(); 
    
        // Simulate resolving of promise 
        deferred.resolve(123); 
        // Note that the 'then' function does not get called synchronously. 
        // This is because we want the promise API to always be async, whether or not 
        // it got called synchronously or asynchronously. 
        expect(resolvedValue).toBeUndefined(); 
    
        // Propagate promise resolution to 'then' functions using $apply(). 
        $rootScope.$apply(); 
        expect(resolvedValue).toEqual(123); 
    })); 
    

    欠点は、あなたのコードは、角に結びついているということです、利点はあなたのコードが平坦であることであり、+から2.xためにポータブルです!

    私は私のテストで約束を返すことができたモカテストランナーのファンでした。あなたはそれを試してみることもできますが、テストのためにコードを具体的に修正する必要があるという欠点もあります。

    4

    このソリューションが役立つことを願います。依存関係を模擬することがテストの際に役立つと感じているアプローチの1つです。私はできるだけ多くのことをコメントしてきました。

    var returnMock, $scope, TestServiceMock, controller; 
    
    beforeEach(module('app')); 
    
    beforeEach(inject(function($controller) { 
        returnMock = { 
         then: jasmine.createSpy(), 
        }; 
        $scope = {}; 
        // first assumption is You are testing TestService extensively, 
        // I don't care about what getData has to do to get results 
        // All I care about is it gets called when I call loadData 
        TestServiceMock = { 
         getData: jasmine.createSpy().and.returnValue(returnMock); 
        }; 
    
        controller = $controller; 
    })); 
    
    it('should load data when loadData function is called and result set is 
    under 1000', function() { 
        controller('TestCtrl', { 
         $scope, 
         TestServiceMock 
        }); 
        // another assumption is your data comes back in such a format 
        // perhaps in the actual code check whether data exists and proceed 
        // or do some other action 
        var returnedData = { 
         data: [ 
          { 
           id: 1, 
           name: 'item 1', 
          }, 
         ] 
        } 
        // when I execute the function/method 
        $scope.loadData(); 
        // I expect getData to be called 
        expect(TestServiceMock.getData).toHaveBeenCalled(); 
        // I expect then to be called and the reason is I mocked it 
        expect(returnMock.then).toHaveBeenCalledWith(jasmine.any(Function)); 
        returnMock.then.calls.mostRecent().args[0](returnedData); 
        // expect data on scope to be equal to my mocked data 
        expect($scope.data).toEqual(returnedData.data); 
        // don't expect any result because 1 < 1000 
        expect($scope.filtered).toEqual([]); 
        expect($scope.filtered.length).toEqual(0); 
    }); 
    
    it('should load data when loadData function is called and result set is over 1000', 
        function() { 
        controller('TestCtrl', { 
         $scope, 
         TestServiceMock 
        }); 
        var returnedData = { 
         data: [ 
          { 
           id: 1, 
           name: 'item 1', 
          }, 
          { 
           id: 1000, 
           name: 'item 1000', 
          }, 
          { 
           id: 1001, 
           name: 'item 1000', 
          }, 
          { 
           id: 1002, 
           name: 'item 1002', 
          } 
         ] 
        } 
        $scope.loadData(); 
        expect(TestServiceMock.getData).toHaveBeenCalled(); 
        expect(returnMock.then).toHaveBeenCalledWith(jasmine.any(Function)); 
        returnMock.then.calls.mostRecent().args[0](returnedData); 
        expect($scope.data).toEqual(returnedData.data); 
        // expect a result because some entries in the mocked data have id > 1000 
        expect($scope.filtered).toEqual([ 
         { 
          id: 1001, 
          name: 'item 1000', 
         }, 
         { 
          id: 1002, 
          name: 'item 1002', 
         }]); 
        expect($scope.filtered.length).toEqual(2); 
    }); 
    

    Official Jasmine Docs広範囲な概念のほとんどを説明します。ソリューションが役立つことを願っています!!!!

    +0

    この回答は私のベーコンを保存した。ありがとう! –

    +1

    あなたがまだベーコンを持っていることを知って嬉しいです:) @KrisMolinari – mahadjr

    関連する問題