2016-02-16 4 views
22

Я пытаюсь проверить свое приложение с помощью Жасмина и получил следующую проблему:
Я посчитаю что-то в функции моего обещания. Вот в чем смысл тестирования моего кода.Жасмин проверить обещание. Затем функция

Вот код моего контроллера:

TestCtrl.$inject = ["$scope", "TestService"]; 
    /* ngInject */ 
    function TestCtrl($scope, TestService) { 
    $scope.loadData = function() { 
     TestService.getData().then(function (response) { 
     $scope.data = response.data; 
     $scope.filtered = $scope.data.filter(function(item){ 
      if(item.id > 1000){ 
      return true; 
      } 
      return false; 
     }) 
     }); 
    } 
    } 

И мой жасмин код теста:

describe('TestService tests', function() { 
    var $q; 
    beforeEach(function() { 
    module('pilot.fw.user'); 
    }); 
    beforeEach(inject(function (_$q_) { 
    $q = _$q_; 
    })); 
    describe('UserController Tests', function() { 

    beforeEach(inject(function (_$httpBackend_, $rootScope, $controller) { 
     this.scope = $rootScope.$new(); 
     this.$rootscope = $rootScope; 
     this.$httpBackend = _$httpBackend_; 
     this.scope = $rootScope.$new(); 
     var TestServiceMock = { 
     getData: function() { 
      var deferred = $q.defer(); 
      var result = [{ 
      "id": 1720, 
      "user": 1132 
      }, 
      { 
       "id": 720, 
       "user": 132 
      }, { 
       "id": 1721, 
       "user": 1132 
      }]; 
      deferred.promise.data = result; 
      deferred.resolve(result); 
      return deferred.promise; 
     } 
     }; 
     this.controller = $controller('TestCtrl', { 
     '$scope': this.scope, 
     'TestService': TestServiceMock 
     }); 
    })); 

    it('test', function(){ 
     this.scope.loadData(); 
     expect(true).toBeTruthy(); 
    }) 
    }); 
}); 

Странная вещь, которую я не понимаю (протестировано с бревнами консольных):

  • Мое обещание создано и возвращено
  • My loadD Функция ата вызывается и будет вызывать функцию GetData() из TestService
  • Все внутри то функция не будет выполнена, хотя я возвращаю обещание, как разрешенное

Так как я могу проверить код внутри затем функция?
Спасибо за помощь

ответ

29

жасмин 'это метод принимает сделать параметр, который можно вызвать для тестирования асинхронного

it('Should be async', function(done) { 
    someAsyncFunction().then(function(result) { 
    expect(result).toBe(true); 
    done(); 
    }); 
}); 

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

Это прямо из документации жасмин, показывая вам, как обращаться с тайм-аут по умолчанию интервал

describe("long asynchronous specs", function() { 
    var originalTimeout; 
    beforeEach(function() { 
    originalTimeout = jasmine.DEFAULT_TIMEOUT_INTERVAL; 
    jasmine.DEFAULT_TIMEOUT_INTERVAL = 10000; 
    }); 

    it("takes a long time", function(done) { 
    setTimeout(function() { 
     done(); 
    }, 9000); 
    }); 

    afterEach(function() { 
    jasmine.DEFAULT_TIMEOUT_INTERVAL = originalTimeout; 
    }); 
}); 

Я думаю, что если он не работает в течение 10 секунд, вы можете иметь дефектные методы. ESPECIALLY, если вы разговариваете с локальным сервером/db. Этот материал должен длиться так долго, только если вы выполняете HEAVY-вычисления или нажимаете внешний api с не очень-то отличным подключением к Интернету. Если все локально (или обрезано/издевается!), То что-либо более 5-10 секунд является определенным красным флагом.

+0

это ('тест', функция (сделано) { TestServiceMock.getData(), а затем (функция (результат) { console.log (результат);. }); ожидать (истина) .toBeTruthy(); сделано();} ) Я попробовал этот путь, но мой журнал консоли не правда даже называется ... же проблема как и раньше:/ - Извините за CodeStyle - Баки для вашей помощи –

+0

Вы звоните сделать ВНЕ «того»! Удостоверьтесь, что «сделано» ВНУТРИ ваших методов тогда: –

+0

В противном случае вы выполняете до того, как обещание даже разрешилось, а тем более узнать, что это за результат. Обратите внимание, как в моем примере я передаю результат обещания в метод ожидания? Это работает только тогда, когда оно разрешено, а внутри «then» –

0

Что касается вашего контроллера, вы должны «вернуть» значения так.

Помните, что вызов чего-то ПОСЛЕ «then» не означает ничего, значения должны называться INSIDE «then». Не после него, или до него. Но внутри. Как Том Грин и тот бедный лоси в Фредди Гот.

+0

Грубые, Я хочу поддержать заявку FGF, но я не думаю, что контроллеры должны возвращать что-либо, если они не возвращают что-то для просмотра. –

1

Позвольте мне рассказать, что я делаю для проектов с угловым 1.x и 2.x +. Используйте инструменты углового тестирования, чтобы избавиться от обратных вызовов/гнезд в ваших асинхронных тестах. В угловом 1.x это означает использование комбинации $ q и $ rootScope. $ Apply(). В угловом 2.x + это означает использование чего-то вроде fakeAsync.

From the Angular 1.x docs

it('should simulate promise', inject(function($q, $rootScope) { 
    var deferred = $q.defer(); 
    var promise = deferred.promise; 
    var resolvedValue; 

    promise.then(function(value) { resolvedValue = value; }); 
    expect(resolvedValue).toBeUndefined(); 

    // Simulate resolving of promise 
    deferred.resolve(123); 
    // Note that the 'then' function does not get called synchronously. 
    // This is because we want the promise API to always be async, whether or not 
    // it got called synchronously or asynchronously. 
    expect(resolvedValue).toBeUndefined(); 

    // Propagate promise resolution to 'then' functions using $apply(). 
    $rootScope.$apply(); 
    expect(resolvedValue).toEqual(123); 
})); 

Недостаток заключается в том, что ваш код привязан к угловому, преимущество, что ваш код является плоским, и это портативный 2.x +!

Я был поклонником тест-лидера мокко, который позволил мне вернуть обещания в моих тестах, вы могли бы попытаться добиться этого, но есть и недостатки, а также необходимость изменения кода специально для теста.

4

Надеюсь, что это решение поможет. Один из подходов, который я нашел полезным при тестировании, - это насмешливые зависимости. Я попытался прокомментировать то, что я сделал как можно больше.

var returnMock, $scope, TestServiceMock, controller; 

beforeEach(module('app')); 

beforeEach(inject(function($controller) { 
    returnMock = { 
     then: jasmine.createSpy(), 
    }; 
    $scope = {}; 
    // first assumption is You are testing TestService extensively, 
    // I don't care about what getData has to do to get results 
    // All I care about is it gets called when I call loadData 
    TestServiceMock = { 
     getData: jasmine.createSpy().and.returnValue(returnMock); 
    }; 

    controller = $controller; 
})); 

it('should load data when loadData function is called and result set is 
under 1000', function() { 
    controller('TestCtrl', { 
     $scope, 
     TestServiceMock 
    }); 
    // another assumption is your data comes back in such a format 
    // perhaps in the actual code check whether data exists and proceed 
    // or do some other action 
    var returnedData = { 
     data: [ 
      { 
       id: 1, 
       name: 'item 1', 
      }, 
     ] 
    } 
    // when I execute the function/method 
    $scope.loadData(); 
    // I expect getData to be called 
    expect(TestServiceMock.getData).toHaveBeenCalled(); 
    // I expect then to be called and the reason is I mocked it 
    expect(returnMock.then).toHaveBeenCalledWith(jasmine.any(Function)); 
    returnMock.then.calls.mostRecent().args[0](returnedData); 
    // expect data on scope to be equal to my mocked data 
    expect($scope.data).toEqual(returnedData.data); 
    // don't expect any result because 1 < 1000 
    expect($scope.filtered).toEqual([]); 
    expect($scope.filtered.length).toEqual(0); 
}); 

it('should load data when loadData function is called and result set is over 1000', 
    function() { 
    controller('TestCtrl', { 
     $scope, 
     TestServiceMock 
    }); 
    var returnedData = { 
     data: [ 
      { 
       id: 1, 
       name: 'item 1', 
      }, 
      { 
       id: 1000, 
       name: 'item 1000', 
      }, 
      { 
       id: 1001, 
       name: 'item 1000', 
      }, 
      { 
       id: 1002, 
       name: 'item 1002', 
      } 
     ] 
    } 
    $scope.loadData(); 
    expect(TestServiceMock.getData).toHaveBeenCalled(); 
    expect(returnMock.then).toHaveBeenCalledWith(jasmine.any(Function)); 
    returnMock.then.calls.mostRecent().args[0](returnedData); 
    expect($scope.data).toEqual(returnedData.data); 
    // expect a result because some entries in the mocked data have id > 1000 
    expect($scope.filtered).toEqual([ 
     { 
      id: 1001, 
      name: 'item 1000', 
     }, 
     { 
      id: 1002, 
      name: 'item 1002', 
     }]); 
    expect($scope.filtered.length).toEqual(2); 
}); 

Official Jasmine Docs подробно объясняет большинство концепций. Надеюсь, что решение поможет !!!!

+0

Этот ответ спас мой бекон. Благодаря! –

+1

Мне приятно знать, что у вас все еще есть ваш бекон :) @ KrisMolinari – mahadjr

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