0

Таким образом, у меня есть контроллер, как это:Как проверить angularjs поведения асинхронного контроллера без использования тайма-аута

angular.module('someModule').controller('someController',function(productService) { 
    $scope.products = []; 
    $scope.init = function() { 
     aService.fetchAll().then(function(payload) { 
      $scope.products = filterProducts(payload.data); 
     }); 
    } 
    $scope.init(); 

    function filterProducts(products) { 
     //for each of products filter some specific ones 
     return filteredProducts; 
    } 
}); 

Я пишу тест, который будет вызывать $ scope.init() и должен убедиться, что продукты фильтруют соответствующим образом. Я насмешливый $ httpBackend поэтому код выглядит следующим образом:

describe("someController", function() { 
    "use strict"; 
    var $controller; //factory 
    var controller; //controller 
    var $rootScope; 
    var $state; 
    var $stateParams; 
    var $injector; 
    var $scope; 
    var $httpBackend; 
    var productService; 

    beforeEach(function(){ 
     angular.mock.module("someModule") 


     inject(function (_$rootScope_, _$state_, _$injector_, $templateCache, _$controller_, _$stateParams_, _$httpBackend_, _productService_) { 
      $rootScope = _$rootScope_; 
      $state = _$state_; 
      $stateParams = _$stateParams_; 
      $injector = _$injector_; 
      $controller = _$controller_; 
      $httpBackend = _$httpBackend_; 
      productService = _productService_; 
     }); 
     controller = $controller("someController", {$scope: $scope, $state: $state}); 
    }); 


    it("init() should filter products correctly",function(){ 
     //Arrange 
     var expectedFilteredProducts = ["1","2"]; 
     var products = ["0","1","2"]; 
     $httpBackend.whenGET("api/products").respond(products); 

     //Act 
     $scope.init(); 

     //Assert 
     setTimeout(100,function(){ 
      expect($scope.products).toEqual(expectedFilteredProducts); 
     }); 

     $httpBackend.flush(); 
    }); 
}); 

Проблема заключается в том, что без SetTimeout тест не проходит. Есть ли способ проверить, что я пытаюсь сделать без него, и не вводя сложные $ q/обещания только для теста? В качестве дополнительной заметки productService возвращает обещание $ http. Благодарю.

Edit: SetTimeout делает пробный запуск, но не утверждения не происходит ..

+0

Если '$ scope.init()' вернул обещание, это было бы намного проще. (и для этого требуется только добавить 7 символов) –

+1

Я считаю, что это '$ httpBackend.flush()', что вы хотите; выполните его после раздела '// Act', и ожидание будет работать без таймаута. Также обратите внимание, что контроллер * уже вызвал * 'scope.init()', поэтому вам не нужно вызывать его снова в тесте. –

+0

@NikosParaskevopoulos, который исправил это! Также с помощью setTimeout тест выполнялся, но ничего не утверждал. Вы можете отправить более подробный ответ, и я его приму. В моем исходном коде у меня было $ httpBackend.flush() после действия. Теперь я воссоздаю контроллер и вызываю init только для этого теста. Спасибо –

ответ

1

На основе комментариев, проблема заключалась в том, что $httpBackend.flush() должна быть выполнена до ожиданий. Фактически он решает все запросы, которые он обучил разрешать (и их соответствующие обещания), чтобы ожидания могли выполняться по завершенным обещаниям.

Также рекомендуется использовать $httpBackend.verifyNoOutstandingExpectation()/$httpBackend.verifyNoOutstandingRequest() после испытаний.

Также обратите внимание, что контроллер уже вызвал scope.init(), поэтому вызов его снова в тесте является избыточным - и может даже вызвать сбои в зависимости от конкретного случая.

Также для setTimeout работает, но не утверждает ничего: использование этого в спецификации делает эту спецификацию асинхронной. Вы должны определить спецификацию с done обратного вызова и вызова из асинхронного кода, когда тест действительно закончил, как:

it("init() should filter products correctly",function(done) { 
    ... 
    //Assert 
    setTimeout(100, function() { 
     ... 
     done(); 
    }); 
}); 

Примечание снова, что угловые издевается обеспечивают способы избежать использования setTimeout на 99,9% время, даже службы $interval/$timeout должным образом издеваются!

Смежные вопросы