2

私はおそらくこれを間違ってやっていますが、それを修正する方法がわかりません。

リソース (ngResource) を使用するコントローラーをテストしたいのですが、リソースのテスト ダブルとして Spy を使用して、実際には http 呼び出しを行わないようにしたいと考えています。以下のコードでは、コントローラーの検索機能をテストしたいだけです。

コントローラ:

controllers = angular.module('app.controllers');
controllers.controller('landingCtrl', ['$scope', '$q', 'categoryResource', function ($scope, $q, categoryResource) {

    $scope.search = function (text) {
        console.log('searching for: ' + text);
        var deferred = $q.defer();
        categoryResource.query({ searchTerm: text }, function (result) {
            if (result.length == 0) {
                deferred.resolve(['No results found']);
            } else {
                deferred.resolve(result);
            }
        });
        return deferred.promise;
    }
}]);

サービス:

var services = angular.module('app.services');    
services.factory('categoryResource', ['$resource', function ($resource) {
    var resource = $resource('/api/category');    
    return resource;
}]);

着陸制御の仕様:

describe('Controller: landingCtrl ', function () {

    var $q,
        $rootScope,
        $scope;

    beforeEach(module('ngResource'));
    beforeEach(module('app.services'));
    beforeEach(module('app.controllers'));

    beforeEach(inject(function (_$rootScope_, _$q_) {
        $q = _$q_;
        $rootScope = _$rootScope_;
    }));

    // mock any depencencies, like scope. $resource or $http
    beforeEach(inject(function ($controller, $injector, categoryResource) {
        $scope = $rootScope.$new();

        spyOn(categoryResource, 'query').andCallFake(function (searchText) {
            console.log('query fake being called');
            var deferred = $q.defer();
            deferred.resolve(['Test', 'Testing', 'Protester']);
            return deferred.promise;
        });

        landingCtrl = $controller('landingCtrl', {
            '$scope': $scope,
            '$q': $q,
            'categoryResource': categoryResource
        });
    }));

    afterEach(inject(function ($rootScope) {
        $rootScope.$apply();
    }));

    it('should return words with "test" in them"', function () {
        $scope.search('test').then(function (results) {
            console.log(results);
            expect(results).toContain('Test');
        });
        $scope.$apply();
    });
});

テストはエラーなしで実行されますが、約束を解決することなく合格するため、「then」関数内のコードは呼び出されません。私は何を間違っていますか?

上記と失敗するはずのテストでプランカーを作成しました。

http://plnkr.co/edit/adE6fTajgbDoM33rtbZS?p=preview

4

1 に答える 1

3

あなたの仕様は嘲笑しているcategoryResource.query()ため、約束を返しますが、コントローラーはそれを期待していません。コールバックを呼び出しquery()て渡し、そのコールバック内で処理を行います。言い換えれば、仕様はコントローラーの動作をテストしていません。

固定仕様は次のとおりです。

spyOn(categoryResource, 'query').andCallFake(function (searchText, callback) {
    console.log('query fake being called');
    callback(['Test', 'Testing', 'Protester']);
});

...

it('should return words with "test" in them"', function () {
    var results;

    $scope.search('test').then(function (_results_) {
        console.log(results);
        results = _results_;
    });
    $scope.$apply();

    expect(results).toContain('Test');
});

ワーキングプランカー

期待をthen()コールバックの外に移動したことに注意してください。そのため、約束が解決されない場合、テストは中断されます。

于 2015-05-14T16:33:25.810 に答える