Тестирование пользовательских сценариев
Гробов Сергей
Даша - ручной тестировщик
Рабочий процесс | Регресс |
---|---|
Agile-команда | Тестовый набор из 60 кейсов |
Взрослый и стабильный проект | Фича добавляет N кейсов |
Релиз каждые 3 дня | Проверка на десктопах |
Перед релизом регресc | Проверка на Android + iOS |
Воркфлоу | Регресс |
---|---|
Agile-команда | Тестовый набор из 60 кейсов |
Взрослый и стабильный проект | Фича добавляет N кейсов |
Релиз каждые 3 дня | Проверка на популярных десктопах |
Перед релизом регресc | Проверка на Android + iOS |
Интеграционные тесты, которые воздействуют на систему через ее внешние интерфейсы и проверяют ожидаемую реакцию системы через эти же интерфейсы
Браузер сам «делает» действия согласно тест-кейсу
Фреймворк для написания
end-to-end тестов
Умеют записывать действия в браузере в команды Selenium для повторного воспроизведения
Плагин для Firefox
Плагин для Firefox
# Устанавливаем hermione
npm install hermione --save
module.exports = {
sets: {
// путь до тестов
desktop: {
files: 'tests/desktop'
}
},
browsers: {
// определяем браузер
firefox: {
desiredCapabilities: {
browserName: 'firefox'
}
}
}
};
// test/desktops/example-1.js
var assert = require('assert');
describe('github', function() {
it('should find hermione', function() {
return this.browser
.url('https://github.com/gemini-testing/hermione')
.getText('#readme h1')
.then(function(title) {
assert.equal(title, 'Hermione')
});
});
});
> hermione
✘ github should find hermione [firefox] - 42ms
Total: 1 Passed: 0 Failed: 1 Skipped: 0 Retries: 0
1) github should find hermione
in file tests/desktop/example-1.js
firefox
✘ Error: connect ECONNREFUSED 127.0.0.1:4444
Центральный узел, который получает все запросы тестов и распределяет их по надлежащим узлам (браузерам).
module.exports = {
sets: {
desktop: {
files: 'tests/desktop'
}
},
browsers: {
chrome: {
desiredCapabilities: {
browserName: 'firefox'
}
}
},
// ссылка на Selenium Grid
gridUrl: `http://USERNAME:ACCESSKEY
@hub-cloud.browserstack.com:80/wd/hub`
};
> hermione
✓ github should find hermione [firefox] - 6551ms
Total: 1 Passed: 1 Failed: 0 Skipped: 0 Retries: 0
Правило: Секреты хранить в переменных окружения
module.exports = {
/* ... */
gridUrl: `http://${process.env.USERNAME}
:${process.env.ACCESSKEY}
@hub-cloud.browserstack.com:80/wd/hub`,
};
// package.json
"scripts": {
"test": "hermione"
}
# Запуск
USERNAME=username ACCESSKEY=accesskey npm test
> hermione
✓ github should find hermione [firefox] - 6551ms
Total: 1 Passed: 1 Failed: 0 Skipped: 0 Retries: 0
Есть браузеры различных версий
Платно
Сложно делать отладку
Нельзя тестировать localhost
Установить JDK (Java Development Kit)
# Установка selenium-standalone
npm install selenium-standalone --save-dev
# Установка необходимых драйверов браузеров
./node_modules/.bin/selenium-standalone install
# Запуск сервера
./node_modules/.bin/selenium-standalone start
module.exports = {
sets: {
desktop: {
files: 'tests/desktop'
}
},
browsers: {
chrome: {
desiredCapabilities: {
browserName: 'firefox'
}
}
},
gridUrl: 'http://localhost:4444/wd/hub'
};
- Зайти на rasp.yandex.ru/trains
- Выбрать город прибытия
- Нажать кнопку «Узнать расписание и цены»
- Отсортировать по цене
ОР: Каждая последующая цена будет больше предыдущей
const assert = require('assert');
describe('Проверка страницы расписания поездов:', () => {
it('должны отображаться цены в порядке возрастания' +
'при сортировке по цене', async function() {
const browser = this.browser;
const url = 'https://rasp.yandex.ru/trains';
await browser.url(url);
const actualUrl = await browser.getUrl();
assert.equal(actualUrl, url);
/* ... */
});
});
> hermione
✓ Проверка страницы расписания поездов: должны отображаться цены
в порядке возрастания при сортировке по цене [firefox] - 7491ms
Total: 1 Passed: 1 Failed: 0 Skipped: 0 Retries: 0
const assert = require('assert');
describe('Проверка страницы расписания поездов:', () => {
it('должны отображаться цены в порядке возрастания' +
'при сортировке по цене', async function() {
const browser = this.browser;
const url = 'https://rasp.yandex.ru/trains';
await browser.url(url);
await browser.setValue(???, 'Екатеринбург');
/* ... */
});
});
цель, идентифицирующая элемент на странице веб-приложения
CSS Query Selector - #id
XPATH - //input[@id = 'to']
другие виды селекторовИщем семантичное для элемента свойство (атрибут, класс и тп)
Проверяем уникальность функцией document.querySelectorAll
const assert = require('assert');
describe('Проверка страницы расписания поездов:', () => {
it('должны отображаться цены в порядке возрастания' +
'при сортировке по цене', async function() {
const browser = this.browser;
const url = 'https://rasp.yandex.ru/trains';
await browser.url(url);
await browser.setValue('#to', 'Екатеринбург');
/* ... */
});
});
const assert = require('assert');
describe('Проверка страницы расписания поездов:', () => {
it('должны отображаться цены в порядке возрастания' +
'при сортировке по цене', async function() {
const browser = this.browser;
const url = 'https://rasp.yandex.ru/trains';
await browser.url(url);
await browser.setValue('#to', 'Екатеринбург');
// клик по кнопке "Узнать расписание и цены"
await browser.click('.SearchForm__submit');
/* ... */
});
});
const assert = require('assert');
describe('Проверка страницы расписания поездов:', () => {
it('должны отображаться цены в порядке возрастания' +
'при сортировке по цене', async function() {
const browser = this.browser;
const url = 'https://rasp.yandex.ru/trains';
await browser.url(url);
await browser.setValue('#to', 'Екатеринбург');
await browser.click('.SearchForm__submit');
// клик по селекту типа сортировки
await browser.click('.SearchSorting__field');
/* ... */
});
});
> hermione
✘ Проверка страницы расписания поездов: должны отображаться цены
в порядке возрастания при сортировке по цене [firefox] - 4492ms
Total: 1 Passed: 0 Failed: 1 Skipped: 0 Retries: 0
1) Проверка страницы расписания поездов: должны отображаться цены
в порядке возрастания при сортировке по цене
in file tests/desktop/first.js
firefox
✘ Error: An element could not be located on the page using
the given search parameters.
const assert = require('assert');
describe('Проверка страницы расписания поездов:', () => {
it('должны отображаться цены в порядке возрастания' +
'при сортировке по цене', async function() {
const browser = this.browser;
const url = 'https://rasp.yandex.ru/trains';
await browser.url(url);
await browser.setValue('#to', 'Екатеринбург');
await browser.click('.SearchForm__submit');
// ожидаем, что загрузочная анимация пропадет
await browser.waitForVisible('.Overlay__container',
5000, true);
await browser.click('.SearchSorting__field button');
/* ... */
});
});
const assert = require('assert');
describe('Проверка страницы расписания поездов:', () => {
it('должны отображаться цены в порядке возрастания' +
'при сортировке по цене', async function() {
const browser = this.browser;
const url = 'https://rasp.yandex.ru/trains';
await browser.url(url);
await browser.setValue('#to', 'Екатеринбург');
await browser.click('.SearchForm__submit');
await browser.waitForVisible('.Overlay__container',
5000, true);
await browser.click('.SearchSorting__field button');
await browser.waitForVisible('[data-value=price]',
1000);
await browser.click('[data-value=price]');
/* ... */
});
});
const assert = require('assert');
describe('Проверка страницы расписания поездов:', () => {
it('должны отображаться цены в порядке возрастания' +
'при сортировке по цене', async function() {
const browser = this.browser;
const url = 'https://rasp.yandex.ru/trains';
await browser.url(url);
await browser.setValue('#to', 'Екатеринбург');
await browser.click('.SearchForm__submit');
await browser.waitForVisible('.Overlay__container',
5000, true);
await browser.click('.SearchSorting__field button');
await browser.waitForVisible('[data-value=price]',
2000);
await browser.click('[data-value=price]');
const prices = await browser
.getText('.TariffsListItem__price');
checkPrices(prices);
});
});
function checkPrices(prices) {
let prev = 0;
prices.forEach(price => {
let curPrice = Number(price.replace(/\D+/g, ''));
assert(curPrice >= prev, 'Каждая последующая цена' +
'должна быть больше предыдущей');
prev = curPrice;
})
}
Во многих тестах используется проверка:
browser.waitForVisible('.Overlay__container', 5000, true);
Если селектор экрана загрузки поменяется - придется переписывать все тесты
Разделение кода тестов и описания страниц
//page-object.js
module.exports = {
overlay: {
container: '.Overlay__container'
}
};
const PO = require('../../page-object');
/* ... */
await browser.waitForVisible(PO.overlay.container, 5000, true);
/* ... */
module.exports = {
browsers: {
chrome: {
desiredCapabilities: {
browserName: 'chrome',
version: '59.0'
},
// сколько параллельно тестов будет проходить
sessionsPerBrowser: 2,
windowSize: '1440x1000'
},
firefox: {
desiredCapabilities: {
browserName: 'firefox'
}
}
},
sets: [{
files: ['tests/desktop'],
// в каких браузерах запустить тесты
browsers: ['chrome', 'firefox']
}],
// количество повторных попыток тестов
retry: 1
};
tests ├── desktop │ ├── desktop-1.js │ ├── desktop-2.js │ ├── desktop-3.js │ └── ... └── touch ├── touch-1.js ├── touch-2.js ├── touch-3.js └── ...
Пропустили дефект в проде, хотя все автотесты проходили
При «сломанной» верстке тесты проходят
describe('Проверка страницы расписания поездов:', () => {
it('должен отображаться футер', async function() {
const browser = this.browser;
const url = 'https://rasp.yandex.ru/trains';
await browser.url(url);
await browser.assertView('plain',
'.LandingFooter');
});
});
> hermione
Проверка страницы расписания поездов: должен отображаться футер
[firefox] - 4616ms
Total: 1 Passed: 0 Failed: 1 Skipped: 0 Retries: 0
1) Проверка страницы расписания поездов: должен отображаться футер
in file tests/desktop/first.js
firefox
✘ NoRefImageError: can not find reference image at
/screens/d8fae21/firefox/plain.png for "plain" state.
const path = require('path');
module.exports = {
sets: {
desktop: {
files: 'tests/desktop'
}
},
browsers: {
firefox: {
desiredCapabilities: {
browserName: 'firefox'
}
}
},
screenshotsDir: test => path.join(path.dirname(test.file),
'screens', test.id(), test.browserId),
};
hermione --update-refs
describe('Проверка страницы расписания поездов:', () => {
it('должен отображаться футер', async function() {
const browser = this.browser;
const url = 'https://rasp.yandex.ru/trains';
await browser.url(url);
await browser.assertView('plain',
'.LandingFooter', {
ignoreElements: [
'.Footer__copyright'
]
});
});
});
> hermione
✓ Проверка страницы расписания поездов:
должен отображаться футер [firefox] - 7491ms
Total: 1 Passed: 1 Failed: 0 Skipped: 0 Retries: 0
написание кейсов → тестирование новых фич → регресс
написание кейсов → тестирование новых фич → написание новых тестов → запуск и наблюдение