Некоторые теории о внешнем тестировании и основанные наCypress
Специфическая практика тестирования E2E.
Некоторые мысли об автоматизированном тестировании переднего плана
Одна из болевых точек ежедневной разработки бизнес-проектов — внешний интерфейс.回归测试
, то неизбежно щелкнуть по нему вручную, но если вы измените общий компонент или функцию, вы должны щелкнуть на главной странице проекта повсюду, чтобы увидеть, есть ли какая-либо проблема. использованный проектGraphQL
Если схема не будет обновлена вовремя, страница, которую вы не заметите, зависнет, и тогда вы можете подождать, чтобы открыть проблему или сообщить об ошибке онлайн 😐
Щелкать вручную не только утомительно, но и ненадежно, и нет гарантии, что функции, требующие регрессионного тестирования, будут тестироваться каждый раз. Чтобы решить эту болевую точку, мы должны упомянуть前端的自动化测试
. Было бы здорово запускать тесты через командную строку и интегрировать автоматизированное тестирование CI.
Однако отечественные заводы еще не сформировали хорошую практику автоматизированного тестирования фронтенда, когда речь заходит об автоматизированном тестировании, все думают о тестировании бэкенда. На нескольких технических конференциях (JSConf, GMTC и т. д.) очень мало тем, посвященных фронтенд-тестированию, и некоторые из них также обсуждаются иностранными фронтенд-инженерами или QA делятся созданием тестовых платформ.
По моему опыту,Фронтенд-тестирование для бизнес-проектовЭто все "неловко". Если это библиотека средств разработки, качество может быть гарантировано с помощью модульного тестирования, если это библиотека компонентов пользовательского интерфейса, это может быть достигнуто с помощьюStorybookдля визуального и моментального тестирования. Так что раньше, каждый раз, когда я думал о том, как интегрировать автоматизированное тестирование в бизнес-проекты, я чувствовал, что понятия не имею, с чего начать (и несколько раз меня пугало больше тестового кода, чем бизнес-кода).
Однако в бизнес-проекте не так много инструментальных функций, требующих модульного тестирования (большинство из них используют lodash или другие сторонние библиотеки для решения сложной логической обработки), а компоненты пользовательского интерфейса в основном напрямую используют более зрелый ant-mobile, ant -дизайн и др. В решении не так много компонентов UI, которые нужно разрабатывать в бизнес-проектах.Большинство из них представляет собой вторичную инкапсуляцию на основе сторонних компонентов UI в сочетании с бизнес-логикой (собственно, ant-design тоже ставит свои компоненты отдельно вGitHub.com/react-compo…сохраняется).
Сценарии, которые нуждаются в автоматизированном тестировании в бизнес-проектах, в основном хотят охватить основные пути использования пользователей, такие как вход и регистрация, добавление покупок в корзину, просмотр заказов, изменение личной информации и т. д., которые тесно связаны с логика рендеринга интерфейса UI.Необходимо проверить, являются ли отправка формы, автоматический переход и рендеринг данных этих страниц ненормальными.
Итак, здесь мы можем разобраться с нашими потребностями:
- Может имитировать операцию ввода щелчка пользователя, управляемую событиями, чтобы проверить, соответствует ли рендеринг страницы ожидаемому.
- Можно использовать командную строку для запуска тестов, можно интегрировать в CI
- Легкая и эффективная, среду легко построить, а тестовый код легко написать (в конце концов, это дополнение к гибкой разработке и непрерывной интеграции, а не тест в ссылке QA, поэтому его нельзя оставлять позади)
Размышляя об этом, нетрудно обнаружить, что E2E-тестирование больше всего необходимо во внешних бизнес-проектах, но, как показано в тестовой пирамиде на заглавном изображении, E2E-тестирование находится на вершине пирамиды, а выполнение E2E-тестирования дорого и медленно. следовательноCypressКак того требует время, Cypress предоставляет комплексное решение, от E2E на вершине пирамиды тестирования до интеграционного тестирования и модульного тестирования.
Cypress
Cypress — это готовый фреймворк для E2E-тестирования, разработанный на основе API Mocha. Он не зависит от интерфейсных фреймворков или других библиотек инструментов для тестирования. автоматически захватывать и записывать скриншоты экрана, реализовывать путешествия во времени и отлаживать в процессе тестирования и т. д.
Подводя итог, преимущества Cypress:
- Простая настройка и быстрая интеграция в существующие проекты
- Поддерживает все уровни тестирования (т. е. вышеупомянутые тесты e2e, интеграционные тесты, модульные тесты и т. д.)
- Моментальные снимки могут быть созданы для каждого шага теста, легко отлаживать
- Все узлы DOM на веб-странице могут быть получены и обработаны
- Функция автоматического повтора, Cypress несколько раз повторит попытку на текущем узле, а затем сделает вывод, что тест не пройден.
- Легко интегрируется в системы CI
По сравнению с другими аналогичными инструментами тестирования, такими как Selenium, Puppeteer и Nightwatch, синтаксис тестового кода Cypress проще и более удобен для интерфейсных инженеров, обеспечивая легкий вес и эффективность платформы.
Кратко опишите, как им пользоваться (подробнее см.Руководство по официальному сайту):
Установить:
yarn add cypress --dev
Добавьте в скрипты npm вашего проекта:
{
"scripts": {
"cypress:open": "cypress open"
}
}
Конфигурация в корневом каталогеcypress.json
:
{
"baseUrl": "http://localhost:8080", // 本地启动的 webpack-dev-server 地址
"viewportHeight": 800, // 测试环境的页面视口高度
"viewportWidth": 1280 // 测试环境的页面视口宽度
}
npm run cypress:open
Это открыло тестовый графический интерфейс локально, готовый к тестированию.
Используйте пример из официальной документации, чтобы проиллюстрировать, как написать тестовый код:
describe('My First Test', function() {
it('Gets, types and asserts', function() {
cy.visit('https://example.cypress.io')
cy.contains('type').click()
// Should be on a new URL which includes '/commands/actions'
cy.url().should('include', '/commands/actions')
// Get an input, type into it and verify that the value has been updated
cy.get('.action-email')
.type('fake@email.com')
.should('have.value', 'fake@email.com')
})
})
Это действительно было проверено:
- Откройте целевую страницу, вот образецexample.cypress.io, на самом деле это должна быть локально запускаемая серверная страница в проекте, напримерhttp://localhost:8080
- Найдите кнопку с текстовым содержимым «тип» в dom страницы и нажмите на нее (если кнопка не отображается на странице, тест не запускается)
- После нажатия кнопки страница должна перейти на страницу, содержащую «/commands/actions» в маршруте.
- В dom этой страницы вы можете найти поле ввода с именем класса ".action-email". После ввода в него "fake@email.com" значение поля ввода должно быть "fake@email.com". '
Семантика тестового кода лучше, объем кода невелик и нет необходимости писать много асинхронной логики.
До сих пор я испытал конфигурацию установки и локальное тестирование, все в порядке, много функций, относительно простое начало работы и несложная интеграция в проект.
Покрытие тестами и непрерывная интеграция (на примере Gitlab)
Любые тесты, не интегрированные в CI, просто игрушки и не в счет. Итак, давайте посмотрим на производительность Cypress.
Мы надеемся, что Cypress можно настроить для выполнения разных тестовых команд на разных этапах разработки. Например, когда вы инициируете PR для функциональной ветки, вы можете выполнить интеграционное тестирование в текущей ветке.Когда вы достигнете основной ветки, вам необходимо рассчитать тестовое покрытие и передать данные на платформу проверки качества, такую как Sonar ( вы также можете установить тестовое покрытие, если тестовое покрытие не соответствует xx%), сбой теста и т. д.).
Итак, давайте сначала посмотрим, как рассчитывается тестовое покрытие. Вычисление тестового покрытия Cypress кажется функцией, которая была добавлена позже, и конфигурация немного сложна.
еще можно уточнитьСправочный документ, просто краткое введение в блоге:
Сначала установите зависимости:
npm install -D @cypress/code-coverage nyc istanbul-lib-coverage
Затем настройте конфигурацию в Cypress:
// cypress/support/index.js
import '@cypress/code-coverage/support'
// cypress/plugins/index.js
module.exports = (on, config) => {
on('task', require('@cypress/code-coverage/task'))
}
Документация здесь только представлена, если в проекте используется TypeScript, этого недостаточно, я просмотрела официальный пример на github и обнаружила, что нужно сделать еще несколько шагов:
npm i -D babel-plugin-istanbul
настроить его.babelrc
{
"plugins": ["istanbul"]
}
Измените его сноваcypress/plugins/index.js
// cypress/plugins/index.js
module.exports = (on, config) => {
on('task', require('@cypress/code-coverage/task'))
on('file:preprocessor', require('@cypress/code-coverage/use-babelrc'))
}
"cy:run": "cypress run && npm run test:report",
"instrument": "nyc instrument --compact=false client instrumented",
"test:report": "npm run instrument && npx nyc report --reporter=text-summary",
пройти черезcypress run
Вы можете запускать тесты прямо в командной строке, не запуская GUI, эту команду следует использовать при использовании в CI.
Посмотрите на результаты, очень доволен.
Покрытие E2E-тестов Cypress также можно комбинировать с модульными тестами или с помощью тестов других фреймворков, таких как Jest.Конкретный метод можно найти на официальном сайте.
Давайте возьмем Gitlab CI runner в качестве примера, чтобы увидеть, как Cypress интегрируется в CI:
// .gitlab-ci.yml
variables:
npm_config_cache: "$CI_PROJECT_DIR/.npm"
CYPRESS_CACHE_FOLDER: "$CI_PROJECT_DIR/cache/Cypress"
stages:
- test
- sonar
cache:
paths:
- .npm
- node_modules/
- cache/Cypress
build:
stage: sonar
tags:
- docker
script:
- yarn
- sh ci/sonar.sh
- yarn build
artifacts:
expire_in: 7 day
paths:
- codeclimate.json
- build
cypress-e2e-local:
image: cypress/base:10
tags:
- docker
stage: test
script:
- unset NODE_OPTIONS
- yarn
- $(npm bin)/cypress cache path
# show all installed versions of Cypress binary
- $(npm bin)/cypress install
- $(npm bin)/cypress cache list
- $(npm bin)/cypress verify
- npm run test
artifacts:
expire_in: 1 week
when: always
paths:
- coverage/lcov.info
- cypress/screenshots
- cypress/videos
Здесь мы настраиваем два этапа CI, тестируем и собираем (сканирование с помощью Sonar, отчеты о данных и т. д.) и используем официальный образ Cypress на этапе тестирования.cypress/base:10
. (Другие настройки переменных среды и зависимости, такие как сканирование Sonar, пряжа и т. д., находятся в нашем собственном образе Docker)
где CI выполняет командуnpm run test
Да:
"test": "start-server-and-test start http://localhost:5000 cy:run"
Здесь для упрощения команды используется пакет npmstart-server-and-testРеализовать логику выполнения теста после запуска локального Сервера.
мы тоже.gitlab-ci.yml
установить вartifacts
:
artifacts:
expire_in: 1 week
when: always
paths:
- coverage/lcov.info
- cypress/screenshots
- cypress/videos
Это из гитлабаjob artifactsФункция может быть настроена на загрузку содержимого определенной папки на сервер после завершения определенного шага, и в течение допустимого времени мы можем просматривать или загружать содержимое этих файлов на веб-странице. Таким образом, если тест CI не пройден, мы можем просмотреть видео и снимок провала теста в артефактах, чтобы избежать слепого угадывания Отладка.
Их много в настройке CI, и управление тестовыми случаями может копнуть глубже. Например, тестовый дым в тесте, общий объем теста или тестирование на стороне клиента, тест уровня узла и тому подобное.
Cypress Применимые тестовые сценарии также больше, например, путем установки пользовательских разрешений Cookie разных тестов, введение случайных нажатий PERM.js достигают различных тестов вкладок, значения возврата интерфейсов MOCK, и так далее.
glebbahmutov.com/blog/Это блог главного мейнтейнера Cypress, в котором также записано множество неряшливых операций (таких как проверка контрастности веб-страницы на соответствие условиям и т. д.) Если вам интересно, можете копать дальше.
яма
Одна ошибка, которую я обнаружил в своей практике, заключается в том, что Cypress не поддерживаетfetch
Запросил поддержку (GitHub.com/cypress-IO/…Мок-запросы, решить которые можно только грязным взломом.
Внедрить в проектwhatwg-fetch, а затем изменитьcypress/support/command.js
:
// cypress/support/command.js
Cypress.Commands.add('visitWithDelWinFetch', (path, opts = {}) => {
cy.visit(
path,
Object.assign(opts, {
onBeforeLoad(win) {
delete win.fetch;
},
})
);
});
Таким образом, мы можем проверить решение о перенаправлении входа в систему нашего проекта:
describe('Node server', function() {
it('no cookie get 401', function() {
cy.server()
cy.clearCookies()
cy.route('POST', '**/graphql').as('login')
cy.visitWithDelWinFetch('/');
cy.wait('@login').then((xhr) => {
expect(xhr.status).to.eq(401)
})
})
it('with cookie get 200', function() {
cy.server()
cy.route('POST', '**/graphql').as('loginWithCookie')
cy.visitWithCookie('/');
cy.wait('@loginWithCookie').then((xhr) => {
expect(xhr.status).to.eq(200)
})
// login successfully, so display the content
cy.get('.ant-layout-sider')
cy.get('.ant-layout-content')
})
})
aha~