Насмешка и глушение с транспортиром
Я хочу проверить мое угловое приложение с транспортиром. В приложении есть модуль API, который общается с сервером. Во время этих тестов я хочу макетировать этот модуль Api. Я не хочу делать полные интеграционные тесты, но тесты от пользовательского ввода с ожидаемыми значениями от API. Это не только ускорит тестирование клиента, но и позволит мне проверить его на наличие крайних случаев, таких как ошибки подключения.
Как я могу сделать это с транспортиром? Я только начал настраивать интеграционные тесты.
Я использовал модуль npm protractor, установил selenium, настроил конфигурацию по умолчанию и использовал onProtractorRunner.js, чтобы проверить мои настройки.
Каков рекомендуемый способ издеваться? Я предполагаю, что макет должен быть сделан в браузере, а не непосредственно в тестовом файле. Я предполагаю, что команды в тестовом файле специфичны для транспортира и будут отправлены бегунам селена. Поэтому я не могу делиться объектами javascript во время сеанса и теста.
Я как-то ожидаю, что мне понадобится шпионская библиотека, такая как sinon.js, или она уже включена в транспортир?
Редактировать: я читал об этой проблеме в трекере проблем с транспортирами, что может быть способом сделать это. В основном вы пишете Mock Module в тесте, который отправляется для выполнения в браузере / области приложения.
Изменить: Вот более многообещающие вопросы. Первый говорит о добавлении Mocks в приложение Angular. Второй говорит о издевательстве над бэкэндом.
Это выглядит действительно хорошо, в этом случае Angular App останется в своем первоначальном виде. Однако в настоящее время это работает только с устаревшими сценариями ng.
8 ответов
В этом блоге обсуждаются сценарии предварительного использования Protractor. В частности это охватывает мало знаю addMockModule()
метод объекта браузера Protractor. Этот метод позволяет вам создавать угловые модули в Protractor (например, макеты или заглушки вашего API-модуля) и загружать их в браузер, чтобы заменить реальную реализацию в контексте заданной спецификации или набора спецификаций.
У вас нет доступа к $httpBackend, контроллерам или сервисам из теста транспортира, поэтому идея состоит в том, чтобы создать еще один угловой модуль и включить его в браузер во время теста.
beforeEach(function(){
var httpBackendMock = function() {
angular.module('httpBackendMock', ['ngMockE2E', 'myApp'])
.run(function($httpBackend) {
$httpBackend.whenPOST('/api/packages').respond(200, {} );
})
}
browser.addMockModule('httpBackendMock', httpBackendMock)
})
ngMockE2E позволяет вам создать фальшивую внутреннюю реализацию для вашего приложения. Вот более глубокий пост по теме http://product.moveline.com/testing-angular-apps-end-to-end-with-protractor.html
Я знаю два таких насмешливых фреймворка, которые могут вам помочь. Один из них - ng-apimock, а другой - json-server.
Недавно я начал использовать ng-apimock API для имитации некоторых внутренних вызовов REST. Это кажется хорошим, поскольку я вижу некоторые интересные функции, доступные в этой библиотеке npm. Здесь вы можете определить и выбрать сценарии и предустановки (несколько макетов) и в основном настроить, какой макет использовать для какого тестового примера e2e. По сути, это означает детальный контроль над тестами e2e путем предоставления необходимых данных ответа по мере необходимости. Настроить не так просто, как говорят многие блоги в Интернете, и я определенно могу это подтвердить. Но это похоже на решение для моего варианта использования.
Мне в основном пришлось настроить proxy.conf.json в дополнение к определению макетов и предустановок (необязательно), а также мне пришлось поддерживать некоторую конфигурацию транспортира для работы с этим API.
По сути, вы можете точно настроить, какие значения должны возвращаться с какой конечной точки API при запуске теста e2e, и вместе с этим можно даже отключить изменение того, какие значения должны возвращаться для каждого тестового примера e2e. В этом API есть одна опция, называемая passThrough, что означает, что вы даже можете выбрать этот сценарий, чтобы убедиться, что макеты отключены, а вызовы переходят на ваш настоящий HTTP-сервер.
Если вам нужны более подробные сведения, дайте мне знать, и я, вероятно, смогу предоставить вам подробную информацию о том, как его настроить.
Хотя я и сам не пробовал на данный момент, Angular предоставляет фиктивный $httpBackend для тестов E2E:
http://docs.angularjs.org/api/ngMockE2E/service/%24httpBackend
Итак, взяв страницу документации выше, я подозреваю, что вы можете использовать что-то вроде следующего перед вашими тестами
beforeEach(function() {
$httpBackend.whenGET('/remote-url').respond(edgeCaseData);
});
Я пытался издеваться над некоторыми услугами в транспортире, и после просмотра некоторых блогов я пришел к решению, которое работает для меня. Идея не в том, чтобы делать тяжелые насмешки, а просто генерировать сообщения об ошибках; поскольку для приборов у меня уже есть бэкдор на моем сервере API для заполнения бэкэнда.
Это решение использует $provide.decorator()
просто изменить некоторые методы. Вот как это используется в тестах:
it('should mock a service', function () {
app.mock.decorateService({
// This will return a rejected promise when calling to "user"
// service "login()" method resolved with the given object.
// rejectPromise() is a convenience method
user: app.mock.rejectPromise('login', { type: 'MockError' }),
// You can decorate the service
// Warning! This code get's stringified and send to the browser
// it does not have access to node
api: function ($delegate, $q) {
$delegate.get = function () {
var deferred = $q.defer();
deferred.resolve({ id: 'whatever', name: 'tess' });
return defer.promise;
};
return $delegate;
},
// Internally decorateService converts the function to string
// so if you prefer you can set an string. Usefull for creating your
// own helper methods like "rejectPromise()".
dialog: [
"function ($delegate, $window) {",
"$delegate.alert = $window.alert;",
"return $delegate;",
"}"
].join('\n')
});
// ...
// Important!
app.mock.clearDecorators();
});
Вот код:
App.prototype.mock = {
// This must be called before ".get()"
decorateService: function (services) {
var code = [
'var decorer = angular.module("serviceDecorator", ["visitaste"]);',
'decorer.config(function ($provide) {'
];
for (var service in services) {
var fn = services[service];
if (_.isFunction(fn)) {
code.push('$provide.decorator("'+ service +'", '+ String(fn) +');');
} else if (_.isString(fn)) {
code.push('$provide.decorator("'+ service +'", '+ fn +');');
}
}
code.push('});');
browser.addMockModule('serviceDecorator', code.join('\n'));
},
clearDecorators: function () {
browser.clearMockModules();
},
rejectPromise: function (method, error, delay) {
return [
'function ($delegate, $q) {',
'$delegate.'+ method +' = function () {',
'var deferred = $q.defer();',
'',
'setTimeout(function () {',
'deferred.reject('+ JSON.stringify(error) +');',
'}, '+ (delay || 200) +');',
'',
'return deferred.promise;',
'};',
'',
'return $delegate;',
'}'
].join('\n');
}
};
Я создал небольшой настраиваемый модуль макета, чтобы помочь мне справиться со сценариями успеха и ошибок, возможно, это поможет вам лучше организовать макет.
Вот еще несколько параметров для заглушки HTTP-сервера:
Смысл выполнения сквозных тестов с транспортиром заключается в проверке работоспособности приложения в интеграции. Если вы пытаетесь тестировать элементы пользовательского интерфейса изолированно, проще использовать небольшие элементы из обычных тестов. Точно так же, как AngularJS сам по себе тестирует директивы.
Тем не менее, если вы действительно хотите издеваться, один из способов - создать отдельную сборку вашего приложения с заглушками вместо реальных служб.