【问题标题】:Karma testing controller that calls service with http使用 http 调用服务的 Karma 测试控制器
【发布时间】:2017-01-01 11:51:07
【问题描述】:

谁能告诉我在我的控制器函数 getData 和工厂函数上运行测试的最佳方法。我很困惑,不知道从哪里开始。您将如何为下面的代码编写测试?

myApp.controller('myController', ['$scope', 'myFactory', function ($scope, myFactory) {

    $scope.getData = function(id) {
        var promise = myFactory.GetData('/dta/GetData?Id=' + id);
        promise
        .then(function (success) {
            $scope.result = success;
        }, function (error) {
            $scope.error = true;
        });
    }
});


myApp.factory('myFactory', ['$http', function ($http) {
    return {
        GetData: function (url) {
            return $http.get(url)
            .then(function (response) {
                return response.data;
             }, function (error) {
                return error;
             });
        }
    }
}]);

【问题讨论】:

  • 你想测试什么,你的控制器的getData方法还是你工厂的GetData方法?
  • ...对于前者,您可以使用create a mock (spy) of myFactory。对于后者,使用$httpBackend
  • 我想测试上面看到的所有代码。我不确定有经验的测试人员会做什么。
  • 在测试控制器的getData函数时,我是不是也使用了$httpBackend?

标签: angularjs unit-testing karma-jasmine


【解决方案1】:

您需要单独测试每个组件(这就是单元测试的目的)。所以对于控制器来说是这样的

describe('myController test', () => {
    let scope, myFactory;

    beforeEach(() => {
        myFactory = jasmine.createSpyObj('myFactory', ['GetData']);            

        module('your-module-name');
        inject(function($rootScope, $controller) {
            scope = $rootScope.$new();

            $controller('myController', {
                $scope: scope,
                myFactory: myfactory
            });
        });
    });

    it('getData assigns result on success', inject(function($q) {
        let id = 1, success = 'success';
        myFactory.GetData.and.returnValue($q.when(success));

        scope.getData(id);
        expect(myFactory.GetData).toHaveBeenCalledWith('/dta/GetData?Id=' + id);
        scope.$digest(); // resolve promises
        expect(scope.result).toBe(success);
    }));

    it('getData assigns error on rejections', inject(function($q) {
        myFactory.GetData.and.returnValue($q.reject('error'));

        scope.getData('whatever');
        scope.$digest();
        expect(scope.error).toEqual(true);
    }));
});

对于您的工厂,您将创建一个单独的 describe 并注入和配置 $httpBackend。文档中有很多示例。


仅供参考,您应该省略工厂中的错误处理程序,即

return $http.get(url).then(response => response.data);

或者如果你不喜欢 ES2015

return $http.get(url).then(function(response) {
    return response.data;
});

因为您当前正在将失败的请求转换为成功的承诺。


事实上,我会进一步让您的 GetData 工厂比仅仅 $http 包装器更有用

GetData: function(id) {
    return $http.get('/dta/GetData', {
        params: { Id: id }
    }).then(function(res) {
        return res.data;
    });
}

【讨论】:

  • 我已经将我的工厂修改为 GetData: function (url) {return $http.get(url);} 但是现在行 expect(scope.result).toBe(success);不起作用。我不确定现在应该是什么。
  • @user1024941 你似乎错过了用response.data 解决承诺的部分。不过,这不应该改变你的测试
  • 为什么我需要服务中的 then 子句,什么时候我可以在我的控制器中拥有它并访问 success.data?
  • @user1024941 它在服务中更有意义,因为它封装了$http 部分。如果服务的消费者只需要数据而不需要 HTTP 响应对象上的任何其他属性,那么您应该只使用数据来解决承诺。如果您坚持在控制器中提取数据,则必须将测试更改为 $q.when({data: success}) 以使解析的值具有 data 属性
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-10-10
  • 1970-01-01
  • 2015-03-22
  • 2015-08-04
  • 1970-01-01
  • 2023-03-05
  • 1970-01-01
相关资源
最近更新 更多