paint-brush
Стабильное программное обеспечение: узнайте о возможностях автоматизированных тестовк@igorluchenkov
1,022 чтения
1,022 чтения

Стабильное программное обеспечение: узнайте о возможностях автоматизированных тестов

к Igor Luchenkov6m2024/03/02
Read on Terminal Reader

Слишком долго; Читать

Автоматизированные тесты — это способ протестировать ваше программное обеспечение, не тратя слишком много времени. Существует три типа тестов: модульные, интеграционные и сквозные. Давайте углубимся в каждый вид и поймем, почему каждый из них нам нужен. Модульные тесты выполняются быстро. Изоляция позволяет им запускать их в любой момент времени, локально и в CI, без запуска зависимых сервисов/вызовов API и базы данных. Интеграционные тесты медленнее, но они проверяют, как соединяются части вашего приложения.
featured image - Стабильное программное обеспечение: узнайте о возможностях автоматизированных тестов
Igor Luchenkov HackerNoon profile picture

Эта статья заслуживает вашего внимания, если вы

  • Вы увлечены написанием качественного программного обеспечения и хотите повысить стабильность своего приложения с помощью тестов.


  • Устали от неожиданных ошибок, возникающих в ваших производственных системах.


  • Нужна помощь в понимании того, что такое автоматизированные тесты и как к ним подходить.

Зачем нам нужны автоматизированные тесты?

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


По мере роста продукта становится все больше и больше времени уходит на ручное (например, руками) тестирование каждой функциональности, на которую влияют ваши изменения.


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


Напротив, компьютеры можно запрограммировать на многократное выполнение одного и того же . Итак, давайте делегируем тестирование компьютерам!


Виды тестов

Пирамида тестирования


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

Модульные тесты

Модуль — это небольшой фрагмент логики, который вы тестируете изолированно (не полагаясь на другие компоненты).

Модульные тесты выполняются быстро. Они заканчиваются в течение нескольких секунд. Изоляция позволяет им запускать их в любой момент времени, локально и в CI, без запуска зависимых сервисов/выполнения вызовов API и базы данных.


Пример модульного теста: функция, которая принимает два числа и суммирует их. Мы хотим вызвать его с разными аргументами и подтвердить, что возвращаемое значение правильное.


 // Function "sum" is the unit const sum = (x, y) => x + y test('sums numbers', () => { // Call the function, record the result const result = sum(1, 2); // Assert the result expect(result).toBe(3) }) test('sums numbers', () => { // Call the function, record the result const result = sum(5, 10); // Assert the result expect(result).toBe(15) })


Более интересный пример — компонент React, который отображает некоторый текст после завершения запроса API. Нам нужно смоделировать модуль API, чтобы он возвращал необходимые значения для наших тестов, визуализировал компонент и утверждал, что визуализированный HTML содержит необходимое нам содержимое.


 // "MyComponent" is the unit const MyComponent = () => { const { isLoading } = apiModule.useSomeApiCall(); return isLoading ? <div>Loading...</div> : <div>Hello world</div> } test('renders loading spinner when loading', () => { // Mocking the API module, so that it returns the value we need jest.mock(apiModule).mockReturnValue(() => ({ useSomeApiCall: jest.fn(() => ({ // Return "isLoading: false" for this test case isLoading: false })) })) // Execute the unit (render the component) const result = render(<MyComponent />) // Assert the result result.findByText('Loading...').toBeInTheDocument() }) test('renders text content when not loading', () => { // Mocking the API module jest.mock(apiModule).mockReturnValue(() => ({ useSomeApiCall: jest.fn(() => ({ // Return "isLoading: false" for this test case isLoading: false })) })) // Execute the unit (render the component) const result = render(<MyComponent />) // Assert the result result.findByText('Hello world').toBeInTheDocument() })


Интеграционные тесты

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


Пример интеграционного теста: служба, которая создает пользователей в базе данных. Для этого требуется, чтобы экземпляр БД ( зависимость ) был доступен при выполнении тестов. Мы проверим, что сервис может создавать и извлекать пользователя из БД.


 import db from 'db' // We will be testing "createUser" and "getUser" const createUser = name => db.createUser(name) // creates a user const getUser = name => db.getUserOrNull(name) // retrieves a user or null test("creates and retrieves users", () => { // Try to get a user that doesn't exist, assert Null is returned const nonExistingUser = getUser("i don't exist") expect(nonExistingUser).toBe(null); // Create a user const userName = "test-user" createUser(userName); // Get the user that was just created, assert it's not Null const user = getUser(userName); expect(user).to.not.be(null) })


Сквозные тесты

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


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


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


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


 test('user can log in', () => { // Visit the login page page.goto('https://example.com/login'); // Fill in the login form page.fill('#username', 'john'); page.fill('#password', 'some-password'); // Click the login button page.click('#login-button'); // Assert the welcome message is visible page.assertTextVisible('Welcome, John!') })

Как вы выбираете, какой тип теста написать?

Помните, что сквозные тесты медленнее интеграционных , а интеграционные тесты медленнее модульных .


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


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


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


Клиентские компоненты должны отображать правильный контент и реагировать на взаимодействие с пользователем так, как вы ожидаете от них.


И, наконец, когда нам следует выбирать модульные тесты ? Все небольшие функции, которые можно тестировать изолированно, например sum , суммирующий числа, Button , отображающий тег <button> , являются отличными кандидатами для модульных тестов. Модули идеальны, если вы следуете подходу разработки через тестирование .


Что дальше?

Напишите несколько тестов! (но начните с малого)

  • Установите среду тестирования , подходящую вашему проекту/языку. На каждом языке есть популярная библиотека для тестирования, например Jest / Vitest для JavaScript, Cypress / Playwright для сквозного тестирования (также использует JavaScript), JUnit для Java и т. д.


  • Найдите в своем проекте небольшую функцию и напишите для нее модульный тест.


  • Напишите интеграционный тест для взаимодействия некоторого компонента/сервиса с базой данных.


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


Сделайте все вышеперечисленное один раз, чтобы понять, как это работает. Затем сделайте это снова во время работы над какой-либо функцией или ошибкой. Тогда поделитесь им со своими коллегами, чтобы вы все писали тесты, экономили время и лучше спали по ночам!


Полезные ресурсы: