1. ホーム
  2. javascript

[解決済み] AngularJS Jasmineのユニットテストで、プロミスを返すサービスをモックするにはどうすればよいですか?

2022-05-05 15:25:28

質問

私は myService を使用しています。 myOtherService で、これはリモートコールを行い、promise を返します。

angular.module('app.myService', ['app.myOtherService'])
  .factory('myService', [
    myOtherService,
    function(myOtherService) {
      function makeRemoteCall() {
        return myOtherService.makeRemoteCallReturningPromise();
      }

      return {
        makeRemoteCall: makeRemoteCall
      };      
    }
  ])

のユニットテストを作るには myService をモックする必要があります。 myOtherService のような、その makeRemoteCallReturningPromise メソッドはプロミスを返します。これが私のやり方です。

describe('Testing remote call returning promise', function() {
  var myService;
  var myOtherServiceMock = {};

  beforeEach(module('app.myService'));

  // I have to inject mock when calling module(),
  // and module() should come before any inject()
  beforeEach(module(function ($provide) {
    $provide.value('myOtherService', myOtherServiceMock);
  }));

  // However, in order to properly construct my mock
  // I need $q, which can give me a promise
  beforeEach(inject(function(_myService_, $q){
    myService = _myService_;
    myOtherServiceMock = {
      makeRemoteCallReturningPromise: function() {
        var deferred = $q.defer();

        deferred.resolve('Remote call result');

        return deferred.promise;
      }    
    };
  }

  // Here the value of myOtherServiceMock is not
  // updated, and it is still {}
  it('can do remote call', inject(function() {
    myService.makeRemoteCall() // Error: makeRemoteCall() is not defined on {}
      .then(function() {
        console.log('Success');
      });    
  }));  

上記からわかるように、私のモックの定義には $q を使って読み込まなければなりません。 inject() . さらに、モックを注入するのは module() の前に来るはずです。 inject() . しかし、一度変更したモックの値は更新されません。

どのようにすればよいのでしょうか?

どのように解決するのですか?

あなたのやり方がなぜうまくいかないのかわかりませんが、私は普段からこのように spyOn 関数を使用します。こんな感じ。

describe('Testing remote call returning promise', function() {
  var myService;

  beforeEach(module('app.myService'));

  beforeEach(inject( function(_myService_, myOtherService, $q){
    myService = _myService_;
    spyOn(myOtherService, "makeRemoteCallReturningPromise").and.callFake(function() {
        var deferred = $q.defer();
        deferred.resolve('Remote call result');
        return deferred.promise;
    });
  }

  it('can do remote call', inject(function() {
    myService.makeRemoteCall()
      .then(function() {
        console.log('Success');
      });    
  }));

また $digest を呼び出します。 then 関数が呼び出されます。を参照してください。 テスト セクションの $q ドキュメント .

------edit------

あなたがやっていることをよく見てみると、あなたのコードに問題があることがわかったと思います。このコードでは beforeEach を設定する必要があります。 myOtherServiceMock を全く新しいオブジェクトに変換します。その $provide はこの参照を見ることはありません。既存の参照を更新するだけでよいのです。

beforeEach(inject( function(_myService_, $q){
    myService = _myService_;
    myOtherServiceMock.makeRemoteCallReturningPromise = function() {
        var deferred = $q.defer();
        deferred.resolve('Remote call result');
        return deferred.promise;   
    };
  }