【问题标题】:Angularjs unit testing resolving promisesAngularjs 单元测试解决承诺
【发布时间】:2015-05-14 15:33:27
【问题描述】:

我可能做错了,但我不知道如何解决它。

我想测试一个使用资源 (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”函数中的代码永远不会被调用。我做错了什么?

我已经创建了一个具有上述内容的 plunker 和一个应该失败的测试:

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

【问题讨论】:

    标签: javascript angularjs unit-testing jasmine spy


    【解决方案1】:

    您的规范正在模拟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() 回调之外,因此如果未解决承诺,您的测试将中断。

    【讨论】:

    • 感谢迈克尔的正确回答!它有效,但我不完全明白为什么。它是否以这种方式工作,因为landingCtrl.search() 返回一个promise,并且 categoryResource.query 的签名是 (object, callback) ?
    • @VictorH.Ponce categoryResource.query() 方法不返回承诺;它接收一个回调并稍后调用它。您的规范正在嘲笑它,好像它返回了一个承诺,因此您的控制器没有正确执行(实际上,query() 回调根本没有被执行)。
    猜你喜欢
    • 2013-02-09
    • 2014-03-05
    • 2018-10-30
    • 2023-03-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-04-25
    • 2019-09-01
    相关资源
    最近更新 更多