37

angular アプリケーションの単体テストの作成を開始しようとしていますが、テスト可能な方法でサービスを正確にモックする方法がわからないため、非常に迅速に停止ブロックにヒットします。
REST呼び出しをモックする方法はありますか?それ以外の場合、テストでサービス内のすべてをミラーリングする必要があるように思えますが、これは私には正しくないようですが、テストの作成はかなり新しいので、おそらくこれが想定されている方法です達成すること。どんな助けでも大歓迎です。

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

angular.module('resources.users', ['ngResource'])
.factory('User', function($resource) {
   var resource = $resource('/api/index.php/users/:username', {}, {
      'update': {method: 'PUT'}
   });

   resource.getUser = function(username, successCb) {
      return resource.query({username: username}, successCb);
   };

   return resource;
});

私のテストはこれまでのところ次のもので構成されています。

describe('User', function() {
    var mockUserResource;
    beforeEach(module('resources.users'));
    beforeEach(function() {
        mockUserResource = sinon.stub({
            getUser: function(username) {
                mockUserResource.query({username: username});
            },
            query: function() {}
        });
        module(function($provide) {
            $provide.value('User', mockUserResource);
        })
   });
   describe('getUser', function() {
      it('should call getUser with username', inject(function(User) {
          User.getUser('test');
          expect(mockUserResource.query.args[0][0]).toEqual({username: 'test'});
      }));
   })
});
4

2 に答える 2

31

zsong's answerはこれを理解するのに大いに役立ちましたが、それがどのように機能するかを拡張したいと思います。編集された場合に備えて、ここにコードを再度リストします。

describe('User', function () {
    var mockUserResource, $httpBackend;
    beforeEach(angular.mock.module('myApp'));

    beforeEach(function () {
        angular.mock.inject(function ($injector) {
            $httpBackend = $injector.get('$httpBackend');
            mockUserResource = $injector.get('User');
        })
    });

    describe('getUser', function () {
        it('should call getUser with username', inject(function (User) {
            $httpBackend.expectGET('/api/index.php/users/test')
                .respond([{
                username: 'test'
            }]);

            var result = mockUserResource.getUser('test');

            $httpBackend.flush();

            expect(result[0].username).toEqual('test');
        }));

    });
});

何が起きてる?

1

beforeEach(angular.mock.module('myApp'));

モジュールで定義されたものを注入するように Angular インジェクター ($injectorおよび) に指示します。これは、依存モジュールなしでモジュールの依存関係を定義するものと考えることができます。モジュールで定義されたものを、たとえばモジュール内のコントローラーに注入する方法と比較してください。angular.mock.injectmyAppmyAppangular.module('myOtherApp', ['myApp'])

2

beforeEach(function () {
    angular.mock.inject(function ($injector) {
        $httpBackend = $injector.get('$httpBackend');
        mockUserResource = $injector.get('User');
    })
});

各仕様の前に、function ($injector)依存関係を挿入して関数を実行します。この場合、依存関係 ( $injector) はパラメーター名から暗黙的に解決されます。このスニペットの機能的に同等のバリアントは次のとおりです。

beforeEach(function () {
    angular.mock.inject(['$httpBackend', 'User', function ($httpB, User) {
        $httpBackend = $httpB;
        mockUserResource = User;
    }]);
});

ここでは、代わりに依存関係を明示的に宣言しており、任意のパラメーター名を自由に使用できます。

3

it('should call getUser with username', inject(function (User) {

繰り返しになりますが、テスト関数には、暗黙的に解決されUserたサービスがパラメーターとして挿入されますが、実際には使用されません。

今回はinject呼び出しの周りにラッパー関数がないことに注意してください。inject仕様が現在実行されている場合は、渡された関数をすぐに呼び出しますが、それ以外の場合はラッパー関数を返します (インジェクト ドキュメントソース コードを参照)。そのため、実際にはラッパー関数は必要ありません。beforeEachしたがって、上記のスニペットは次のように記述できます。

beforeEach(angular.mock.inject(function ($injector) {
    $httpBackend = $injector.get('$httpBackend');
    mockUserResource = $injector.get('User');
}));
于 2014-08-05T15:43:54.393 に答える