1. Пишите четкие и описательные тестовые примеры

При разработке тестов Cypress убедитесь, что ваши тестовые примеры четко определены, ясны и описательны. Это облегчает вам и другим членам команды понимание цели каждого теста и ожидаемых результатов. Используйте функции `describe()` и `it()`, предоставляемые Cypress, для организации ваших тестов и предоставления содержательных описаний.

Написание четких и описательных тестовых примеров имеет решающее значение для эффективного тестирования в Cypress. Это помогает поддерживать удобочитаемость и понятность набора тестов. Четко определенный тестовый пример должен описывать тестируемую функциональность, входные данные и ожидаемый результат. Это облегчает группе разработчиков понимание цели каждого теста, устранение неполадок и поддержку набора тестов в долгосрочной перспективе.

Примеры:

Допустим, мы тестируем простую функцию входа в веб-приложение. Нам нужно создать тесты для разных сценариев, таких как действительный логин, неверный логин и пустые поля ввода. Мы можем использовать функции `describe()` и `it()`, предоставляемые Cypress, для организации наших тестов и предоставления осмысленных описаний.

Пример 1 — Тестовый пример для действительного входа в систему:

describe(‘Login functionality’, () => {
 it(‘should log in successfully with valid credentials’, () => {
 // Visit the login page
 cy.visit(‘/login’);

// Enter valid email and password
 cy.get('#email').type('[email protected]');
 cy.get('#password').type('correctpassword');

// Click the login button
 cy.get('#login-button').click();

// Check if the user is redirected to the dashboard
 cy.url().should('include', '/dashboard');

// Check if a success message is displayed
 cy.get('.alert-success').should('be.visible');
 });
});
```

Пример 2 — Тестовый случай для неверного входа в систему:

describe(‘Login functionality’, () => {
 it(‘should show an error message with invalid credentials’, () => {
 // Visit the login page
 cy.visit(‘/login’);

// Enter invalid email and password
 cy.get('#email').type('[email protected]');
 cy.get('#password').type('wrongpassword');

// Click the login button
 cy.get('#login-button').click();

// Check if the user is not redirected
 cy.url().should('not.include', '/dashboard');

// Check if an error message is displayed
 cy.get('.alert-danger').should('be.visible');
 });
});

Пример 3 — Тестовый пример для пустых полей ввода:

describe(‘Login functionality’, () => {
 it(‘should show an error message with empty input fields’, () => {
 // Visit the login page
 cy.visit(‘/login’);

// Leave email and password fields empty
 cy.get('#email').type('');
 cy.get('#password').type('');

// Click the login button
 cy.get('#login-button').click();

// Check if the user is not redirected
 cy.url().should('not.include', '/dashboard');

// Check if an error message is displayed
 cy.get('.alert-danger').should('be.visible');
 });
});

В приведенных выше примерах мы использовали функцию `describe()`, чтобы сгруппировать наши тестовые примеры под общей темой — «Функции входа в систему». Функция `it()` используется для создания отдельных тестовых случаев с понятными и описательными именами. Это облегчает группе разработчиков понимание цели каждого теста и ожидаемых результатов, что обеспечивает эффективное тестирование и отладку.

2. Уделите приоритетное внимание тестированию критически важных функций

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

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

Пример:

В качестве примера рассмотрим приложение электронной коммерции. Некоторые из наиболее важных функций в таком приложении:

1. Регистрация пользователя и вход в систему
2. Просмотр и поиск товаров
3. Добавление товаров в корзину
4. Процесс оформления заказа и оплаты

Вот пример тестового процесса для процесса оформления заказа, который является важной функциональностью:

describe(‘Checkout process’, () => {
 it(‘should complete the checkout process successfully with valid payment details’, () => {
 // Log in as a registered user
 cy.login(‘[email protected]’, ‘correctpassword’);

// Visit the product page
 cy.visit('/product/123');

// Add the product to the shopping cart
 cy.get('#add-to-cart').click();

// Go to the shopping cart
 cy.visit('/cart');

// Click the checkout button
 cy.get('#checkout-button').click();

// Fill in the shipping details
 cy.get('#shipping-name').type('John Doe');
 cy.get('#shipping-address').type('123 Main St');
 cy.get('#shipping-city').type('New York');
 cy.get('#shipping-zip').type('10001');

// Fill in the payment details
 cy.get('#card-number').type('4111111111111111');
 cy.get('#card-expiry').type('1023');
 cy.get('#card-cvv').type('123');

// Click the pay now button
 cy.get('#pay-now-button').click();

// Check if the user is redirected to the order confirmation page
 cy.url().should('include', '/order-confirmation');

// Check if a success message is displayed
 cy.get('.alert-success').should('be.visible');
 });
});

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

3. Используйте шаблон объектной модели страницы

Организуйте тестовый код с помощью шаблона Page Object Model (POM), который включает создание отдельных классов или объектов, представляющих разные области или компоненты вашего приложения. Этот шаблон упрощает поддержку и обновление тестов по мере развития приложения, поскольку любые изменения в структуре приложения или пользовательском интерфейсе могут быть обновлены в соответствующем объекте страницы, не влияя на общую логику тестирования.

Шаблон Объектная модель страницы (POM) — это шаблон проектирования, который обычно используется в автоматизации тестирования для улучшения сопровождения, удобочитаемости и возможности повторного использования кода. Организуя тестовый код с помощью шаблона POM, вы создаете отдельные классы или объекты, которые представляют разные области или компоненты вашего приложения. Каждый объект страницы инкапсулирует функциональность и элементы определенной части приложения, позволяя отделить логику тестирования от фактической реализации пользовательского интерфейса. Это упрощает поддержку и обновление ваших тестов по мере развития приложения, поскольку любые изменения в структуре приложения или пользовательском интерфейсе могут быть обновлены в соответствующем объекте страницы, не влияя на общую логику тестирования.

Пример:

Давайте рассмотрим приложение электронной коммерции со страницей входа и страницей продукта. Мы можем создать объекты страницы для каждой из этих страниц, а затем использовать их в наших тестах Cypress.

1. LoginPage.js — Объект страницы для страницы входа:

class LoginPage {
 visit() {
 cy.visit(‘/login’);
 }

getEmailInput() {
 return cy.get('#email');
 }

getPasswordInput() {
 return cy.get('#password');
 }

getLoginButton() {
 return cy.get('#login-button');
 }

login(email, password) {
 this.getEmailInput().type(email);
 this.getPasswordInput().type(password);
 this.getLoginButton().click();
 }
}

export default LoginPage;

2. ProductPage.js — Объект страницы для страницы товара:

class ProductPage {
 visit(productId) {
 cy.visit(`/product/${productId}`);
 }

getAddToCartButton() {
 return cy.get('#add-to-cart');
 }

addToCart() {
 this.getAddToCartButton().click();
 }
}

export default ProductPage;

3. Использование объектов страницы в тесте Cypress:

import LoginPage from ‘./LoginPage’;
import ProductPage from ‘./ProductPage’;
describe('E-commerce application', () => {
 it('should add a product to the cart after logging in', () => {
 // Create instances of Page Objects
 const loginPage = new LoginPage();
 const productPage = new ProductPage();

// Log in using the LoginPage Page Object
 loginPage.visit();
 loginPage.login('[email protected]', 'correctpassword');'

// Visit the product page and add a product to the cart using the ProductPage Page Object
 productPage.visit('123');
 productPage.addToCart();

// Check if the product was added to the cart
 // … (Assertions based on the application behavior)
 });
});

В этом примере мы создали два объекта Page, LoginPage и ProductPage, для представления страницы входа и страницы продукта нашего приложения электронной коммерции. Затем мы использовали эти объекты страницы в нашем тесте Cypress, чтобы войти в систему и добавить продукт в корзину. Организовав наш тестовый код с помощью шаблона POM, мы можем легко поддерживать и обновлять наши тесты по мере развития приложения, не затрагивая общую логику тестирования.

4. Сделайте тесты устойчивыми к изменениям

Создавайте свои тесты таким образом, чтобы они могли обрабатывать незначительные изменения в приложении без поломок. Этого можно добиться, используя более надежные селекторы (такие как атрибуты данных или уникальные идентификаторы) вместо того, чтобы полагаться исключительно на классы элементов или общие теги элементов. Кроме того, рассмотрите возможность использования встроенной в Cypress возможности повторных попыток для команд и утверждений, которая может помочь справиться с любыми временными несоответствиями в состоянии приложения или пользовательском интерфейсе, такими как задержки загрузки или анимация.

Сделать ваши тесты устойчивыми к изменениям необходимо для поддержания стабильного и эффективного набора тестов. Тесты должны быть разработаны таким образом, чтобы обрабатывать незначительные изменения в приложении без нарушения работы, что экономит время и усилия, затрачиваемые на исправление неработающих тестов. Этого можно достичь, используя более надежные селекторы, такие как атрибуты данных или уникальные идентификаторы, вместо того, чтобы полагаться исключительно на классы элементов или общие теги элементов. Использование надежных селекторов гарантирует, что ваши тесты будут менее подвержены поломке из-за изменений пользовательского интерфейса. Кроме того, встроенная в Cypress возможность повторных попыток для команд и утверждений может помочь справиться с любыми временными несоответствиями в состоянии приложения или пользовательском интерфейсе, такими как задержки загрузки или анимация.

Пример:

Давайте рассмотрим пример тестового сценария для приложения блога, где мы хотим протестировать функциональность добавления комментария к сообщению блога.

1. Во-первых, мы можем использовать атрибуты данных в качестве селекторов, чтобы сделать наши тесты устойчивыми к изменениям пользовательского интерфейса. В HTML приложения мы добавляем атрибуты данных к соответствующим элементам:

<textarea data-cy=”comment-input”></textarea>
<button data-cy=”submit-comment-button”>Submit</button>

2. Далее в нашем тесте Cypress мы используем эти атрибуты данных в качестве селекторов:

describe(‘Blog application’, () => {
 it(‘should add a comment to a blog post’, () => {
 // Visit the blog post page
 cy.visit(‘/blog-post/1’);

// Type a comment into the comment input field
 cy.get('[data-cy=comment-input]').type('This is a sample comment.');

// Click the submit comment button
 cy.get('[data-cy=submit-comment-button]').click();

// Check if the comment is added to the comment list
 cy.contains('.comment', 'This is a sample comment.').should('be.visible');
 });
});

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

3. Кроме того, мы можем использовать встроенную в Cypress возможность повторных попыток для обработки несоответствий в состоянии приложения или пользовательском интерфейсе. Например, если список комментариев загружается асинхронно, мы можем использовать команду cy.contains(), которая автоматически повторяет попытку до тех пор, пока не будет найдено ожидаемое содержимое или не истечет время ожидания:

// Check if the comment is added to the comment list
cy.contains(‘.comment’, ‘This is a sample comment.’).should(‘be.visible’);

В этом примере мы разработали наши тесты, чтобы они были устойчивыми к изменениям, используя более надежные селекторы (атрибуты данных) и используя встроенную возможность повторных попыток Cypress. Это гарантирует, что наши тесты могут обрабатывать незначительные изменения в приложении без сбоев, что приводит к более стабильному и эффективному набору тестов.

5. Сохраняйте тесты модульными и удобными в сопровождении

Разбейте свои тестовые примеры на более мелкие модульные функции или пользовательские команды, которые можно повторно использовать в нескольких тестах. Это не только улучшает читабельность и удобство сопровождения вашего тестового кода, но также помогает уменьшить дублирование кода. Организуйте свои тесты в виде логической структуры папок и рассмотрите возможность использования ловушек (таких как `beforeEach()` или `afterEach()`) для настройки и очистки состояний тестов, гарантируя, что каждый тест изолирован и не мешает другим тестам. .

Сохранение модульности тестов и удобство сопровождения — важная практика автоматизации тестирования. Разбивая тестовые примеры на более мелкие модульные функции или пользовательские команды, вы улучшаете читабельность и удобство сопровождения своего тестового кода, сокращая при этом дублирование кода. Организация тестов в виде логической структуры папок помогает поддерживать порядок в наборе тестов и упрощает навигацию. Кроме того, использование хуков, таких как `beforeEach()` или `afterEach()`, позволяет вам настраивать и очищать состояния тестов, гарантируя, что каждый тест изолирован и не мешает другим тестам.

Пример:

Давайте рассмотрим пример тестового сценария для приложения блога, где мы хотим протестировать функциональность создания новой записи в блоге и удаления записи в блоге. Мы можем создавать собственные команды и использовать хуки, чтобы сделать наши тесты модульными и удобными в сопровождении.

1. Сначала мы создаем собственные команды в файле `cypress/support/commands.js`:

Cypress.Commands.add(‘createBlogPost’, (title, content) => {
 cy.get(‘[data-cy=new-post-title]’).type(title);
 cy.get(‘[data-cy=new-post-content]’).type(content);
 cy.get(‘[data-cy=submit-post-button]’).click();
});

Cypress.Commands.add('deleteBlogPost', (title) => {
 cy.contains('[data-cy=blog-post-title]', title).parent().find('[data-cy=delete-post-button]').click();
});

2. Затем мы используем эти пользовательские команды в наших тестах Cypress, а также используем хук `beforeEach()` для посещения главной страницы приложения блога перед каждым тестом:

describe(‘Blog application’, () => {
 beforeEach(() => {
 // Visit the main page before each test
 cy.visit(‘/blog’);
 });

it('should create a new blog post', () => {
 // Create a new blog post using the custom command
 cy.createBlogPost('Sample Title', 'Sample Content');

// Check if the new blog post is displayed
 cy.contains('[data-cy=blog-post-title]', 'Sample Title').should('be.visible');
 });
it('should delete a blog post', () => {
 // First, create a blog post to delete
 cy.createBlogPost('Post to Delete', 'Content to be deleted');

// Delete the blog post using the custom command
 cy.deleteBlogPost('Post to Delete');

// Check if the blog post is no longer displayed
 cy.contains('[data-cy=blog-post-title]', 'Post to Delete').should('not.exist');
 });
});

В этом примере мы создали пользовательские команды для создания и удаления сообщений в блоге, сделав наши тесты более модульными и удобными в сопровождении. Мы также использовали хук `beforeEach()` для посещения главной страницы перед каждым тестом, гарантируя, что наши тесты изолированы и не мешают другим тестам. Этот подход улучшает читабельность и удобство сопровождения нашего тестового кода, уменьшая дублирование кода.

Следуя этим рекомендациям и рекомендациям, вы сможете разрабатывать эффективные тесты Cypress, которые просты в обслуживании, масштабируемы и способны выявлять потенциальные проблемы в вашем приложении до того, как они попадут в рабочую среду.

Полезные ссылки