6

ご存じのように、ユニット テスト内では、$httpBackend を使用して XHR リクエストをモックする組み込みの angularjs 機能があります。これは、ユニット テストを作成するときに便利です。

最近、ファイルのアップロード時に XHR をモックする必要があり、いくつかの問題を発見しました。

次のコードを検討してください。

var xhr = new XMLHttpRequest();

xhr.upload.addEventListener("progress", uploadProgress(event), false);
xhr.addEventListener("load", uploadComplete(event), false);
xhr.addEventListener("error", uploadError(event), false);
xhr.addEventListener("abort", uploadAbort(event), false);
xhr.open("POST", 'some url');
xhr.send(someData);

私がやりたいのは、XHR リクエストのモックを使用してそのようなコードの単体テストを行うことですが、ここでは $http サービスが使用されていないため、実行できません。

私はこれを試しました(そしてそれは機能しており、$httpBackendで嘲笑することができます):

$http({
    method: 'POST', 
    url: 'some url', 
    data: someData, 
    headers: {'Content-Type': undefined},
    transformRequest: angular.identity})
.then(successCallback, errorCallback);

しかし、この場合、'progress' コールバックと 'abort' コールバックを実装する方法がわかりません (これらは不可欠であり、現在取り組んでいる場合に必要です)。

最新の Angular が promise の進行状況コールバックをサポートしているという情報を見てきました (ただし、$http サービスと統合されているかどうかはわかりません) が、abort コールバックはどうですか?

アイデアはありますか、それとも以前に似たようなものに会ったことがありますか?

4

2 に答える 2

2

$httpテストをより細かく制御したいので、遅延オブジェクトをモックして制御する必要があります。基本的には、$httpプロバイダーをモックし、遅延オブジェクトを公開するカスタム実装を提供してから、それを試します。

$http正しく動作するかどうか心配する必要はありません。動作するはずであり、既にテストされているからです。したがって、それをモックし、コードの一部をテストすることだけを心配する必要があります。

次のようにする必要があります。

describe('Testing a Hello World controller', function() {
  beforeEach(module(function($provide) {
    $provide.provider('$http', function() {
      this.$get = function($q) {
        return function() {
          var deferred = $q.defer(),
              promise = deferred.promise;

          promise.$$deferred = deferred;
          return promise;
        }
      };
    });
  }));

  it('should answer to fail callback', inject(function(yourService, $rootScope) {
    var spyOk = jasmine.createSpy('okListener'),
        spyAbort = jasmine.createSpy('abortListener'),
        spyProgress = jasmine.createSpy('progressListener');

    var promise = yourService.upload('a-file');
    promise.then(spyOk, spyAbort, spyProgress);

    promise.$$deferred.reject('something went wrong');
    $rootScope.$apply();

    expect(spyAbort).toHaveBeenCalledWith('something went wrong');
  }));
});

そして、あなたのサービスは単純です:

app.service('yourService', function($http) {
  return {
    upload: function(file) {
      // do something and
      return $http({...});
    }
  };
});

promises 通知は、最新の RC リリースでのみ利用できることに注意してください。したがって、使用できない場合は、例をもう少し詳しく説明し、XHR イベントなどをモックしてください。

また、KISS の原則に従うために、できればコールバック (失敗、成功、進行) ごとに 1 つのテスト ケースを用意する必要があることに注意してください。

于 2013-09-30T14:22:54.530 に答える