【问题标题】:How to test Controller that calls a service where service uses $http如何测试调用服务使用 $http 的服务的控制器
【发布时间】:2016-07-23 11:36:40
【问题描述】:

我正在尝试测试控制器。控制器使用使用 $http 的服务从 json 文件中获取数据(这个 json 文件只是从服务器返回的响应的模型)

我的问题是,当我测试控制器时,它会创建控制器对象,甚至调用服务。但它不调用 $http 模拟响应。我不确定我哪里出错了。我试着看几个例子,但他们都在使用 $q。

我的服务如下所示:

(function(){
  angular.module('mymodule')
    .factory('MyService', MyService);
  MyService.$inject = ['$http'];

  function MyService($http) {

    var service = {
      retrieveData : retrieveData
    };
    return service;

    function retrieveData(containerLabel){
      var myGrossData = [];
      var isMatchFound = false;
      var myindex = containerLabel.slice(-4);

      return $http.get('app/myGrossData.json').then(function(response) {
          console.log('inside http retrieveData: ');
          myGrossData = response.data;
          var myindexExists = false;

          var mydataObject = [];
          var defaultdata = [];
          angular.forEach(myGrossData, function (myGrossData) {
            if (myindex === myGrossData.myindex) {
              mydataObject = myGrossData;
              isMatchFound = true;
            }

            if(!isMatchFound && myGrossData.myindex === '2006')
            {
              mydataObject = myGrossData;
            }

            if(myGrossData.myindex === '2006'){
              defaultdata = myGrossData;
            }
          });
          if (isMatchFound && response.status === 200)
          {
            return mydataObject;
          }

          else if(!isMatchFound && (response.status === 200 || response.status === 201)){
            return defaultdata;
          }

          else //all other responses for success block
          {
            return 'Incorrect Response status: '+response.status;
          }
        },
        function(error){
          return 'Error Response: '+error.status;
        }
      );
    }   
  };
})();

调用它的控制器是:

(function () {
  'use strict';
  angular
    .module('mymodule', [])
    .controller('MyCtrl', MyCtrl);

  MyCtrl.$inject = ['$scope', 'MyService'];

  function MyCtrl($scope, MyService) {
    var vm = this;
    vm.datafromsomewhere = datafromsomewhere;
    vm.displayData = [];
    vm.disableBarCode = false;
    vm.childCount = 0;
    vm.headertext="Master Container Builder";

    init();

    function init() {
      console.log('MyCtrl has been initialized!');
      console.log(vm.headertext);
    }

    function myfunctionCalledByUI(input) {
      processData(input);
    }

    function processData(containerLabel){      
      MyService.retrieveMasterContainer(containerLabel).then(function(data){
        vm.displayData = data;
      });

      vm.disableBarCode = true;
      vm.childCount = (vm.displayData.childData === undefined) ? 0: vm.displayData.childData.length;
      vm.headertext="Myindex "+vm.displayData.myindex;

      if ( vm.displayData.masterDataId.match(/[a-z]/i)) {
        // Validation passed
        vm.displayData.masterDataId ="No Shipping Label Assigned";
      }
      else
        console.log('else: '+vm.displayData.masterDataId);
      console.log('length of childData: '+vm.childCount);
    }
  }
})();

最后我的规范看起来像这样:

var expect = chai.expect;

describe('Test Controller', function () {

  var rootScope, compile; MyService = {};
  var $scope, $controller;
  beforeEach(module('ui.router'));

  beforeEach(function() {
    module('mymodule');

    inject(function ($rootScope, _$compile_,_$controller_) {
      rootScope = $rootScope;
      compile = _$compile_;
      $scope = $rootScope.$new();

      MyService = jasmine.createSpyObj('MyService', [
        'retrieveData'
      ]);
      $controller = _$controller_('MyCtrl', {
        $scope: $scope
      });
    });

  });




  it('controller should be initialized and data should also be initialized', function() {

    expect($controller).to.not.be.undefined;
    expect($controller).to.not.be.null;
    expect($controller.disableBarCode).to.equal(false);
    expect($controller.childCount).to.equal(0);
    expect($controller.headertext).to.equal("Master Container Builder");
  });

  it(' should process data when containerLabel is called into myfunction', function() {

    $controller.handKeyed('12001');
    expect(MyService.retrieveData).to.have.been.called;
    expect($controller.processData).to.have.been.called;
    expect($controller.disableBarCode).to.equal(true);
    expect($controller.childCount).to.equal(0);
    expect($controller.headertext).to.equal("Master Container Builder");

  });
});

如果有帮助,我正在使用以下技术堆栈:

  1. 角1.5
  2. 离子
  3. 业力茉莉花

代码在我运行时有效。我的问题是,当我运行测试时,它不会在我的 vm.displayData 变量中填充数据。如何让它将一些数据输入服务。我添加了一些日志语句,它完全跳过它。

在所有测试运行后,包括与此无关的测试,然后我看到来自 MyService 的日志语句。我不确定如何处理这个问题。

【问题讨论】:

    标签: angularjs unit-testing promise bdd karma-jasmine


    【解决方案1】:

    我认为您正在寻找的是$httpBackend 服务。它将模拟指示结果的请求。因此,当您的服务点击 url 时,它将返回您传递给 $httpBackend 配置的内容。

    一个简单的例子是:

        it('should list newest by category', function(){
            $httpBackend
                .expectGET(url)
                .respond(techPosts /*YOUR MOCKED DATA*/);
    
            $stateParams.category = 'tech';         
            var controller = $controller('HomeCtrl', { PostsResource: PostsResource, $stateParams: $stateParams });
    
            controller.listNewestPosts();
            $httpBackend.flush();
    
            expect(controller.posts).toEqual(techPosts.posts);
        });
    

    【讨论】:

    • 使用 $httpBackend 作为您的示例不会为我提供来自在 MyCtrl 中调用的 MyService 服务的数据。我用它来为我的服务编写测试(有效)
    猜你喜欢
    • 2017-01-01
    • 1970-01-01
    • 2015-03-22
    • 2023-03-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-08-18
    相关资源
    最近更新 更多