Как создать модульный тест с жасмином при использовании angular-datatables
Я использую angular-datatables в своем проекте, и я хотел бы написать для него модульный тест Jasmine/Karma.
Это код из моего контроллера:
$scope.dtOptions = DTOptionsBuilder.fromSource('/api/books/')
.withBootstrap()
.withPaginationType('simple_numbers')
.withDisplayLength(10)
//.withOption('serverSide', true)
.withOption('processing', true)
.withOption('createdRow', createdRow);
$scope.dtColumns = [
DTColumnBuilder.newColumn('id').withTitle('ID'),
DTColumnBuilder.newColumn('name').withTitle('Name')
DTColumnBuilder.newColumn(null).withTitle('Actions').notSortable()
.renderWith(actionsHtml)
];
Как мне теперь написать для него модульный тест, подделав ответ JSON от /api/books
?
2 ответа
var $scope, $state, DTColumnBuilder, DTOptionsBuilder, createController, $httpBackend;
beforeEach(function () {
DTColumnBuilder = {};
DTOptionsBuilder = {};
$state = {};
$httpBackend = {};
module('app', function ($provide) {
$provide.value('$state', $state);
$provide.value('$httpBackend', $httpBackend);
$provide.value('DTColumnBuilder', DTColumnBuilder);
$provide.value('DTOptionsBuilder', DTOptionsBuilder);
});
inject(function ($controller, $injector) {
$scope = $injector.get('$rootScope').$new();
$state = $injector.get('$state');
$httpBackend = $injector.get('$httpBackend');
DTColumnBuilder = $injector.get('DTColumnBuilder');
DTOptionsBuilder = $injector.get('DTOptionsBuilder');
aliasOfYourController = function () {
return $controller('originalNameOfController', {
$scope: scope,
$state: $state,
DTOptionsBuilder: DTOptionsBuilder,
DTColumnBuilder: DTColumnBuilder
});
}
spyOn($state, 'go');
$httpBackend.flush();
});
afterEach(function() {
$httpBackend.verifyNoOutstandingExpectation();
$httpBackend.verifyNoOutstandingRequest();
});
// Stub out the methods of interest.
DTOptionsBuilder.fromSource = angular.noop;
DTColumnBuilder.bar = function () { return 'bar'; };
});
Природа spy
это то, что позволяет исходной реализации делать свое дело, но записывает все вызовы указанной функции и ассортимент связанных данных.
stub
с другой стороны, это spy
с расширенным API, где вы можете полностью изменить работу указанной функции. Возвращаемое значение, ожидаемые параметры и т. Д.
Предполагая, что мы использовали вышеупомянутый блок beforeEach, DTOptionsBuilder.fromSource
будет noop
с этой точки зрения. Таким образом, было бы безопасно spy
и ожидаем, что метод был вызван.
it('should have been called', function () {
var spy = spyOn(DTOPtionsBuilder, 'fromSource');
aliasOfYourController();
expect(spy).toHaveBeenCalled();
});
Если бы вы хотели манипулировать возвращаемым значением указанной функции, я бы взял sinonjs и сделал его stub
,
it('became "foo"', function () {
DTOptionsBuilder.fromSource = sinon.stub().returns('foo');
aliasOfYourController();
expect($scope.dtOptions).toEqual('foo');
});
Теперь, так как вы работаете с обещаниями, это немного сложнее, но основами для исключения функции, основанной на обещаниях, будет:
- впрыскивать
$q
в ваш файл спецификаций. - Скажи
stub
возвращать$q.when(/** value **/)
в случае разрешенного обещания. - Скажи
stub
возвращать$q.reject(/** err **/)
в случае отклоненного обещания. - Бежать
$timeout.flush()
сбросить все отложенные задачи. И если вы издеваетесь над HTTP-ответом, который вы используете$httpBackend
в ваших юнит-тестах и$httpBackend.flush()
сбросить все отложенные задачи. - Вызвать
done
обратный вызов, чтобы уведомить Jasmine о том, что вы закончили ожидание асинхронных задач (может не потребоваться). Это зависит от тестовой среды / бегуна.
Это может выглядеть примерно так:
it('resolves with "foo"', function (done) {
DTOptionsBuilder.fromSource = sinon.stub().returns($q.when('foo'));
expect($scope.options).to.eventually.become('foo').and.notify(done); // this is taken from the chai-as-promised library, I'm not sure what the Jasmine equivalent would be (if there is one).
aliasOfYourController();
$timeout.flush();
});
И, если вы хотите проверить $state.go('toSomeState')
тогда юнит-тест может быть:
it('should redirected successfully', function() {
var stateParams = {
id: 22,
name: sample
}
functionNameInsideWhichItsBeenCalled(stateParams);
expect($state.go).toHaveBeenCalledWith('toSomeState', {
id: stateParams.id,
name: stateParams.name
});
});
Сейчас многое из этого - просто догадки на данный момент. Довольно сложно настроить полностью работающий набор тестов, если исходный код не будет запущен рядом со мной для перекрестных ссылок, но я надеюсь, что это, по крайней мере, даст вам некоторые идеи о том, как работать с вашими $ httpBackend, шпионами и заглушками.
Чтобы смоделировать ответ http, вы используете $httpBackend в своих модульных тестах.
используйте $httpBackend.expect, если вы хотите, чтобы тест не прошел, если запрос не сделан. Вы также можете определить ложный ответ.
используйте $httpBackend.when, когда вы хотите определить ложный ответ, если запрос сделан, но не делает запрос обязательным.
КОД ОБЪЯСНИТЬ...
КОД КОНТРОЛЛЕРА ДЛЯ ТЕСТИРОВАНИЯ
self.callme = function() {
$http.get('/mypath').then(function() {
console.log("I will be executed when flush is called if the mock API response is 2xx");
}).catch(function() {
console.log("I will be executed when flush is called if the mock API response is NOT 2xx");
});
}
КОД ТЕСТА БЛОКА...
$httpBackend.expectGET('/mypath').respond(200, {data:"fred"});
controller.callme();
// The THEN code has not been executed here
$httpBackend.flush();
// The THEN success code is now executed because we responded with 2xx (200)