web-dev-qa-db-ja.com

ジャスミンで単体テストを行うとき、AngularJSでサービスをどのようにモックしますか?

2つのステートフルサービスshopscheduleに依存するサービスwarehouseがあるとします。ユニットテストのためにschedulewarehoseの異なるバージョンをshopに挿入するにはどうすればよいですか?

私のサービスは次のとおりです。

angular.module('myModule').service('shop', function(schedule, warehouse) {
    return {
        canSellSweets : function(numRequiredSweets){
             return schedule.isShopOpen()
                 && (warehouse.numAvailableSweets() > numRequiredSweets);
        }
    }
});

ここに私のモックがあります:

var mockSchedule = {
    isShopOpen : function() {return true}
}
var mockWarehouse = {
    numAvailableSweets: function(){return 10};
}

私のテストは次のとおりです。

expect(shop.canSellSweets(5)).toBe(true);
expect(shop.canSellSweets(20)).toBe(false);
65
KevSheedy
beforeEach(function () {
  module(function ($provide) {
    $provide.value('schedule', mockSchedule);
  });
});

モジュールは、angular-mocksモジュールによって提供される関数です。文字列引数を渡すと、対応する名前のモジュールがロードされ、すべてのプロバイダー、コントローラー、サービスなどが仕様に使用できます。通常、それらは注入機能を使用してロードされます。コールバック関数を渡すと、Angularの$ injectorサービスを使用して呼び出されます。次に、このサービスはコールバック関数に渡された引数を見て、どの依存関係をコールバックに渡す必要があるかを推測しようとします。

52
Attila Miklosi

Atillaの答えを改善し、KevSheedyのコメントに直接答えて、module('myApplicationModule')のコンテキストで次のことを行います。

beforeEach(module('myApplicationModule', function ($provide) {
  $provide.value('schedule', mockSchedule);
}));
36
Matt Richards

CoffeeScriptではいくつかの問題が発生するため、最後にnullを使用します。

beforeEach ->
  module ($provide) ->
    $provide.value 'someService',
      mockyStuff:
        value : 'AWESOME'
    null

詳細はこちらをご覧ください

https://docs.angularjs.org/guide/services#unit-testing

$ provideサービスを利用したい場合。あなたの場合

$provide.value('schedule', mockSchedule);
6
Adam

ジャスミンを使用している場合、ジャスミンのスパイで呼び出しをモックする別の方法があります( https://jasmine.github.io/2.0/introduction.html#section-Spies )。

これらを使用すると、関数呼び出しの対象となり、必要に応じて元のオブジェクトへの呼び出しを許可できます。テストファイルの先頭が$ provideとモックの実装で詰まるのを防ぎます。

あなたのテストの前に、私は次のようなものを持っています:

var mySchedule, myWarehouse;

beforeEach(inject(function(schedule, warehouse) {

  mySchedule = schedule;
  myWarehouse = warehouse;

  spyOn(mySchedule, 'isShopOpen').and.callFake(function() {
    return true;
  });

  spyOn(myWarehouse, 'numAvailableSweets').and.callFake(function() {
    return 10;
  });

}));

また、これは$ provideメカニズムと同様の方法で動作するはずです。スパイする注入された変数のローカルインスタンスを提供する必要があることに注意してください。

1
bwobbones

私は最近、AngularJSでのモックテストを簡単にするngImprovedTestingモジュールをリリースしました。

あなたの例では、ジャスミンテストで交換するだけで済みます...

beforeEach(module('myModule'));

...と...

beforeEach(ModuleBuilder.forModule('myModule').serviceWithMocks('shop').build());

NgImprovedTestingの詳細については、紹介ブログ投稿をご覧ください: http://blog.jdriven.com/2014/07/ng-improved-testing-mock-testing-for-angularjs-made-easy/ =

1
Emil van Galen

このようにモジュールにモックを置く方が簡単です:

    beforeEach(function () {
    module('myApp');
    module({
      schedule: mockSchedule,
      warehouse: mockWarehouse
     }
    });
  });

インジェクションを使用して、テスト前の操作のためにこれらのモックへの参照を取得できます。

var mockSchedule;
var mockWarehouse;

beforeEach(inject(function (_schedule_, _warehouse_) {
     mockSchedule = _schedule_;
     mockWarehouse = _warehouse_;
}));
1
Gal Morad

私の答えがそれほど役に立たないことを願っていますが、$provide.service

beforeEach(() => {
    angular.mock.module(
      'yourModule',
      ($provide) => {
        $provide.service('yourService', function() {
          return something;
        });
      }
    );
  });
1
Clemens Basler