Привет! Меня зовут Алёна Луцик, я QA-инженер в команде Авито. За время работы я много раз убеждалась, что разработчик и тестировщик смотрят на код по-разному. Это заметно, когда нужно обеспечить покрытие unit-тестами.

Разработчику выгоднее написать один большой тест, который зайдёт в максимальное число ветвлений и покажет, как работают разные функции. При этом QA-инженеру нужны автотесты, которые выявят ошибки в бизнес-логике и помогут улучшить продукт в целом. 

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

Что поможет QA-инженеру договориться с разработчиками

Одна из целей QA-инженера — обеспечить высокое качество продукта без избыточного тестирования. Это не значит, что придётся писать все автотесты своими руками. Но нужно понимать, какая функциональность уже проверяется автотестами от коллег-разработчиков. Для этого важно много общаться и обсуждать код.

Что я делаю в своей команде:

  • Объясняю, что важно тестировщику.

Разработчик не всегда понимает, почему QA-инженер хочет знать о unit-тестах. Коллегам кажется, что достаточно поддерживать требуемый процент покрытия кода. Они пишут собственные автотесты для проверки всех функций и не понимают, зачем их переделывать. Поэтому важно проговаривать, что именно тестировщик хочет от разработчиков, — так продукт станет лучше. 

Стоит говорить прямо: «Я хочу понимать, что покрывают unit-тесты. Мне это нужно, чтобы правильно и не избыточно покрывать функциональность. Я трачу время на понимание задачи, чтобы не тратить его потом на лишние тесты».

  • Учусь читать код.

Важный навык для QA-инженера — умение читать код. Можно пройти курсы по языку программирования, который используют в команде. Кроме этого, нужно разбираться, что делает конкретный участок кода. 

На курсах разработки задачи обычно сформулированы довольно прозрачно и код решения кажется понятным. В реальных проектах всё сложнее. Проговорите вместе с коллегой из разработки, что делает каждая функция и unit-тест для неё. Тогда станет понятнее, какие тесты можно улучшить с точки зрения бизнес-процесса.

  • Обсуждаю тесты заранее.

Тестировщик смотрит на функцию как на часть бизнес-процесса, а разработчик отвечает за внутреннюю логику её работы. На стыке этих задач появляются полезные unit-тесты. Поэтому обсуждать unit-тестирование лучше на этапе, когда разрабатывается функциональность или формулируется задача. Тогда QA-инженер понимает, что можно покрыть на уровне unit-тестов, а что нужно проверять на более поздних этапах. 

При тестировании полезно «двигаться влево» — подключаться к работе как можно раньше
При тестировании полезно «двигаться влево» — подключаться к работе как можно раньше

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

В чём польза единого подхода к unit-тестам

Какие результаты мы получили, когда начали применять шаги, о которых я рассказываю выше:

  • стали тестировать больше негативных сценариев;

  • увеличили покрытие dataset;

  • нашли сценарии для деградации.

Увеличили число негативных тест-кейсов

Разработчики в unit-тестах проверяют, что все функции работают корректно. Для этого нужен позитивный тест, который проанализирует несколько основных ветвлений. Такой подход хорошо покрывает код тестами. Но остаются непроверенные кейсы — например, логирование ошибок.

Читайте также: Ошибка.log(): как логируются ошибки в мобильном приложении

При этом для QA-инженера важно узнать, что именно не работает. Тесты должны проверять все ветвления функции и обработчики ошибок. Поэтому тестировщику нужно участвовать в код-ревью и менять unit-тесты, если требуется.

Улучшили покрытие dataset

На уровне unit-тестов удобно проверять допустимые значения в коде. Обычно в dataset значений добавляют что-то очевидное: специальные символы, большие числа, строки. Мы решили улучшить эти проверки и добавили дополнительные варианты. Например, стали проверять пустые значения, сокращённые записи дробных чисел и предел переменной int.

Dataset filter_int до и после ревью от QA-инженера: добавили проверки пустых значений, сокращённых записей дробных чисел, предел переменной int
Dataset filter_int до и после ревью от QA-инженера: добавили проверки пустых значений, сокращённых записей дробных чисел, предел переменной int

Внедрили поиск сценариев для деградации

Чтобы понять, как это работает, возьмём гипотетические «Наш сервис» и «Другой сервис» — они взаимодействуют друг с другом и обмениваются данными. Причём «Другой сервис» — это фронт-слой, его видят пользователи. «Наш сервис» — промежуточный, он подключается к базе данных, ещё одному нашему сервису и соседнему. Затем собирает их ответы и передаёт на фронт-слой.

Пример неприятной ситуации: все сервисы отдают «Нашему сервису» ошибку 500 — сервер не может обработать запрос и вернуть ответ
Пример неприятной ситуации: все сервисы отдают «Нашему сервису» ошибку 500 — сервер не может обработать запрос и вернуть ответ

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

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

Для важной информации — возвращаем ошибку 500. Для не очень важной — ищем способ продолжить пользовательский сценарий
Для важной информации — возвращаем ошибку 500. Для не очень важной — ищем способ продолжить пользовательский сценарий

От базы данных «Наш сервис» получает информацию, без которой невозможно продолжить пользовательский сценарий. Он передаёт «Другому сервису» ошибку. А данные от ещё одного нашего сервиса не так важны для сценария. «Наш сервис» возвращает «Другому сервису» пустой массив и идёт дальше. Это считается деградацией сценария.

Пример из реальной жизни: когда создаётся объявление в Авито, на экране появляется аватарка пользователя, который его размещает. Если эта аватарка по какой-то причине не прогружается, нет смысла останавливать прорисовку экрана и передавать на фронт ошибку. Для пользовательского сценария полезнее продолжить работу без аватарки. 

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

Как я отслеживаю unit-тесты у себя в команде

Кроме общения с разработчиками, QA-инженеру нужно посчитать общее число unit-тестов для пирамиды тестирования. В своей команде я использую простой подход: все unit-тесты в коде отмечаются комментарием и тегом ID. В комментарии понятно и кратко описано, что именно проверяет этот тест. Тег показывает, к какой фиче будет прикреплён тест и его номер для подсчёта в пирамиде. 

Позитивный unit-тест для SomeFunc:

// tagID 4637 Параметры. Позитивный тест получателя параметров
func Test_SomeFunc_Positive(t *testing.T) {
    contrl := gomock.NewController (t)
    defer ctrl.Finish ()
    categoryID := map[string]interface{}{"first": 123}

    composition := NewMockComposition(ctrl)

    result, err := composition.GetRequestFormByParams(context.Background(), categoryID)

    assert.Nil(t, err)
    assert. Equal(t, expexted: 123, result)
}

Тесты выгружаются во внутреннее хранилище, которое автоматически считает их число. В нём учитываются unit-тесты, интеграционные, компонентные и UI-тесты. Здесь же можно посмотреть сгенерированную пирамиду тестирования: сколько проверок на каждом уровне выбранной фичи и какое общее тестовое покрытие.

Пример пирамиды, которую рисует хранилище на основе данных о тестах
Пример пирамиды, которую рисует хранилище на основе данных о тестах

Зелёные блоки показывают процент покрытого автотестами кода, красные — непокрытого.

Если хотите лучше понимать, что из себя представляет наша тестохранилка, прочитайте статью.

Итоги: как договориться о unit-тестах

Мой подход к обсуждению unit-тестов помог повысить качество продукта в команде, поэтому я советую QA-инженерам попробовать его в своей работе. Напомню, что нужно делать: 

  • Объяснять коллегам из разработки, почему для вас важно разбираться в unit-тестах.

  • Учиться читать код и понимать, что делает каждая функция.

  • Заранее проговаривать, какую функциональность можно протестировать на уровне unit.

Предыдущая статья: Как мы улучшили типографику на сайте Авито

Комментарии (0)