AngularJs:茉莉花测试服务

AngularJs:茉莉花测试服务,angularjs,jasmine,karma-runner,Angularjs,Jasmine,Karma Runner,我做了这个控制器 app.controller('controller',['$scope','httpServices',function($scope,httpServices){ $scope.items= undefined; httpServices.getItems( function(items){ $scope.items= items; }); }]); 我写了这个测试 describe('controller', functi

我做了这个控制器

  app.controller('controller',['$scope','httpServices',function($scope,httpServices){
    $scope.items= undefined;

    httpServices.getItems( function(items){
        $scope.items= items;
    });
}]);
我写了这个测试

 describe('controller', function () {
        beforeEach(inject(function ($rootScope, $controller) {
            scope = $rootScope.$new();
            controller = $controller('controller', {
                '$scope': scope
            });
        }));
        it('defined', function () {
            expect(scope.items).toBeUndefined();
        })
    });

如何在调用服务之后测试scope.items?

我假设您的服务httpServices正在发出一些http请求。因此,您应该使用该服务来测试控制器

类似这样,请注意我在代码中的注释:

describe('Your specs', function() {
  var $scope,
      $controller,
      $httpBackend;

  // Load the services's module
  beforeEach(module('yourApp'));

  beforeEach(inject(function(_$controller_, $rootScope, _$httpBackend_) {
    $scope = $rootScope.$new();
    $httpBackend = _$httpBackend_;
    $controller = _$controller_;

    //THIS LINE IS VERY IMPORTANT, HERE YOU HAVE TO MOCK THE RESPONSE FROM THE BACKEND 
    $httpBackend.when('GET', 'http://WHATEVER.COM/API/SOMETHING/').respond({});

    var createController = function(){
      $controller('controller', {$scope: $scope});
    }
  }));

  describe('Your controller', function() {  
    it('items should be undefined', function() {
      createController();
      expect(scope.items).toBeUndefined();
    });

    it('items should exist after getting the response from the server', function () {
        //THIS LINE IS ALSO VERY IMPORTANT, IT EMULATES THE RESPONSE FROM THE SERVER
        $httpBackend.flush();
        expect(scope.items).toBeDefined();
    });
  });
});

问题标题说明这是为了测试服务,但问题代码看起来像是在尝试测试控制器。此答案描述了如何测试控制器

如果您正在测试调用httpServices.getItems的控制器,那么您需要模拟它/存根getItems,以便

在测试中控制它 不假设真实的httpServices.getItems有任何行为。毕竟,您测试的是控制器,而不是服务。 一种方法是在创建控制器之前调用beforeach块,提供一个getItems的伪实现,该实现只保存传递给它的回调

var callback;
beforeEach(inject(function(httpServices) {
  callback = null;
  spyOn(httpServices, 'getItems').and.callFake(function(_callback_) {
    callback = _callback_;
  });
});
在测试中,您可以调用这个回调函数,传入一些虚假数据,并测试在作用域上是否正确设置了这些数据

it('saves the items passed to the callback on the scope', function () {
  var testItems = {};
  callback(testItems);
  expect($scope.items).toBe(testItems);
});
可以看出,这一点正在发挥作用


如果您确实想测试httpServices.getItems本身,则需要进行单独的测试。假设getItems调用$http,那么您很可能需要使用$httpBackend来处理模拟响应。最有可能的是,这些测试不会实例化任何控制器,并且我怀疑不需要在任何范围上执行任何操作。

在第二个测试中,它应该是expectscope.items.toBeDefined@当然,我只是改变了。但是为什么呢?旧代码是100%等效的:expectscope.items.not.toBeUndefined与expectscope.items.tobedefinedah my bad!我不知道,我道歉@阿披舍卡因不担心,不需要道歉。我最初做的是expectscope.items.not.toBeUndefined,因为在第一次调用中我做的是expectscope.items.toBeUndefined,我认为看到差异会更加明显。但都是一样的;在我的测试中,我一直使用.toBeDefined和.not.toBeDefined,并且从不知道变体的存在。正如你所说,两者都是一样的,使用其中一种只是个人的选择-你为什么不从httpServices.getItems返回承诺?