Angularjs 유닛 테스트 솔루션

질문:

내가 잘못했나 봐요. 그런데 어떻게 복구해야 할지 모르겠어요.
자원 (ng Resource) 을 사용하는 컨트롤러를 테스트하고 싶습니다. 이 자원에 대한 이중 테스트를 스파이로 사용하면 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"함수의 코드는 영원히 호출되지 않습니다.내가 뭘 잘못했지?
나는 이미 상술한 방법으로 Plunker를 만들었고 테스트에 실패할 것이다.
http://plnkr.co/edit/adE6fTajgbDoM33rtbZS?p=preview

답안

규범이 시뮬레이션 중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');
});
Working Plunker
예상을 then() 리셋 밖으로 옮겼기 때문에, 약속이 해결되지 않으면 테스트가 파괴될 수 있습니다.