3

次の角度コントローラーがあります

function IndexCtrl($scope, $http, $cookies) {   

    //get list of resources
    $http.get(wtm.apiServer + '/v1/developers/me?access_token=' + $cookies['wtmdevsid']).
    success(function(data, status, headers, config) {
        // snip 
      }).
      error(function(data, status, headers, config) {
        // snip
      });

$scope.modal = function() {
      // snip
}

return;
}

私がやろうとしているのは、$http サービスの get メソッドをモックすることです。これが私の単体テストコードです:

describe('A first test suite', function(){
    it("A trivial test", function() {
         expect(true).toBe(true);
    });
});

describe('Apps', function(){
describe('IndexCtrl', function(){
    var scope, ctrl, $httpBackend;
    var scope, http, cookies = {wtmdevsid:0};

    beforeEach(inject(function($injector, $rootScope, $controller, $http) {
        scope = $rootScope.$new();

         ctrl = new $controller('IndexCtrl', {$scope: scope, $http: $http, $cookies: cookies});
         spyOn($http, 'get');
         spyOn(scope, 'modal');

    }));

    it('should create IndexCtrl', function() {
        var quux = scope.modal();
        expect(scope.modal).toHaveBeenCalled();
        expect($http.get).toHaveBeenCalled();
    });
  });
});

これを実行すると、ReferenceError: wtm is not defined が発生します。

wtm はグローバル オブジェクトであり、もちろん、テストを実行するときに定義されません。なぜなら、wtm で宣言されているコードは、テストを実行するときに実行されないからです。私が知りたいのは、実際の $http.get 関数が呼び出される理由と、実際に実際の関数を呼び出さないようにスパイまたはスタブを設定する方法です。

(グローバルに対する inb4 嫌悪: 私の同僚の 1 人が、私たちのコードからそれらを因数分解する任務を負っています :) )

4

3 に答える 3

4

ここで説明した方法で使用されるすべてのグローバルは、$windowサービスを通じて使用することをお勧めします。

window.wtm などの使用可能なすべてのグローバル変数は、$window.atm でも使用できます。

次に、wtm 参照を完全にスタブ化し、既に説明したのと同じ方法でスパイできます。

 var element, $window, $rootScope, $compile;

  beforeEach(function() {
    module('fooApp', function($provide) {
        $provide.decorator('$window', function($delegate) {

            $delegate.wtm = jasmine.createSpy();

            return $delegate;
        });
    });

    inject(function(_$rootScope_, _$compile_, _$window_) {
        $window = _$window_;
        $rootScope = _$rootScope_;
        $compile = _$compile_;
    });     

  });
于 2013-04-07T18:55:50.017 に答える
4

whenGETテストの前にメソッドを接続する必要があり$httpBackendます。beforeEach()テストの機能で設定してみてください... 「モックバックエンドを使用したユニットテスト」の下に良い例があります。

于 2012-11-16T18:20:24.893 に答える
1

特別なニーズを処理する $httpBackend の周りにカスタム ラッパー モックを作成できるかもしれません。

詳細には、Angular は同じ名前のコンポーネントを後着順で上書きます。これは、モジュールをロードする順序がテストで重要であることを意味します。

同じ名前の別のサービスを定義し、最初のサービスの後にロードすると、最初のサービスの代わりに最後のサービスが注入されます。例えば:

apptasticMock.service("socket", function($rootScope){
  this.events = {};

  // Receive Events
  this.on = function(eventName, callback){
    if(!this.events[eventName]) this.events[eventName] = [];
    this.events[eventName].push(callback);
  }

  // Send Events
  this.emit = function(eventName, data, emitCallback){
    if(this.events[eventName]){
      angular.forEach(this.events[eventName], function(callback){
        $rootScope.$apply(function() {
          callback(data);
        });
      });
    };
    if(emitCallback) emitCallback();
  }

});

このサービスはまったく同じインターフェイスを提供し、ソケットを介して通信しないことを除いて、元のサービスとまったく同じように動作します。これは、テストに使用したいサービスです。

angular のロード シーケンスを念頭に置いて、テストは次のようになります。

describe("Socket Service", function(){
  var socket;

  beforeEach(function(){
    module('apptastic');
    module('apptasticMock');

    inject(function($injector) {
      socket = $injector.get('socket');
    });
  });

  it("emits and receives messages", function(){
    var testReceived = false;

    socket.on("test", function(data){
      testReceived = true;
    });

    socket.emit("test", { info: "test" });
    expect(testReceived).toBe(true);
  });

});

ここで重要なのは、が のmodule('apptasticMock')後に実行されることmodule('apptastic')です。これにより、元のソケット実装がモック化されたもので上書きされます。残りは、通常の依存性注入手順です。

私が書いたこの記事は、さらに詳しく説明しているので、あなたにとって興味深いかもしれません。

于 2013-03-24T16:12:54.877 に答える