【问题标题】:How to write unit test for http request?如何为http请求编写单元测试?
【发布时间】:2015-07-30 08:20:08
【问题描述】:

我正在尝试对我的服务进行单元测试

在我的测试控制器中

myService.getItem('/api/toy/' + scope.id).success(
   function(toy) {
       $scope.toy = toys.details;
   }
);

我的服务

angular.module('toyApp').service('myService', ['$http',
    function($http) {
        var service = {};
        return {
            getItem: function(url) {
                return $http.get(url);
            },
        };
    }
]);

测试文件。

describe('toy ctrl', function () {
    var $httpBackend, ctrl, myService;

    beforeEach(module('toyApp'));

    beforeEach(inject(function (_$controller_, _$httpBackend_, _$rootScope_, __myService_) {
        scope = _$rootScope_.$new();
        $httpBackend = _$httpBackend_;
        myService = _myService_;

        ctrl = _$controller_('toyCtrl', {
            $scope: scope
        });      

    }));

    describe('call my service', function() {
        it('should make request when app loads', function() {
            $httpBackend.expectGET('/api/toy/123').respond({id:123, detail:456 });
            myService.getItem('/api/toy/123').then(function(toy){
                expect(scope.toy.detail).toBe(456);
            })
            $httpBackend.flush();   
     })
 })

我来了

Error: Unexpected request: GET /api/toy/123
No more request expected

如果我取出$httpBackend.flush(),错误就消失了,但它不会覆盖

  function(toy) {
       $scope.toy = toys.details;
   }

部分。我想介绍函数调用,但不知道该怎么做。任何人都可以帮助我吗? 非常感谢

【问题讨论】:

  • 你是在单元测试控制器还是服务(当应用加载看起来像控制器时应该发出请求)?
  • 我正在控制器内部测试服务
  • 好的。在这种情况下,您可以模拟您的服务并将其注入控制器。并针对范围测试价值。基本上我想说的是,当你对控制器进行单元测试时,你只需要测试控制器逻辑 myService.getItem('/api/toy/123') 实际上是无关紧要的。
  • @PSL 你能举个例子吗? +1

标签: javascript angularjs unit-testing jasmine karma-jasmine


【解决方案1】:

似乎您正在“单元”测试控制器,因此您不必引入图片中的服务,因为您只需要测试控制器逻辑。您可以创建一个模拟服务并在测试中创建控制器时注入它。

例子:

var mockItem = {details:{//somestuff}, id:'1'};// set up a mock object to test against later
//....
beforeEach(inject(function (_$controller_, _$httpBackend_, _$rootScope_, _$q_) {
    scope = _$rootScope_.$new();
    $httpBackend = _$httpBackend_;

    //Set up mock
    myService = jasmine.CreateSpyObj('myService', ['getItem']); 
    myService.getItem.and.returnValue($q.when(mockItem ));

    ctrl = _$controller_('toyCtrl', {
        $scope: scope,
        myService: myService //<-- Pass it here
    });      

}));


  //.....Assuming you are making the call when controller is instantiated
  it('should make request when app loads', function() {
     expect(myService.getItem).toHaveBeenCalled();
     //You could also check as below
     //expect(myService.getItem).toHaveBeenCalledWith(expectedidpassedin);
     scope.$digest(); //Resolve $q promise callback
     expect($scope.toy).toEqual(mockItem .details);
  });

如果您专门单独对您的服务进行单元测试,您可以这样做:

it('should make request when app loads', function() {
        var resp;
        $httpBackend.expectGET('/api/toy/123').respond({id:123, detail:456});
        myService.getItem('/api/toy/123').then(function(response){
            resp = response.data;
        });
        $httpBackend.flush();   
        expect(resp.detail).toEqual(456);
 });

在您的控制器中而不是链接 success 使用 then

 myService.getItem('/api/toy/' + scope.id).then(
   function(response) {
       $scope.toy = response.toys.details;
   });

【讨论】:

  • 谢谢我在使用.then时遇到错误,如果我使用then似乎找不到响应。 +1
  • @FlyingCat 这应该不是问题。 then 是 q 承诺的一部分。成功是 http 承诺的一部分,它只是 q 承诺的包装。然后应该随处可用。还要确保您在测试中执行$q.when(data)。另请注意,当您使用 then response.data 时,您会在 success 回调中获得第一个参数
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-02-15
  • 2019-08-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多