Привет! Я QA Automation Engineer в Scalable Solutions. Наша компания, как и многие другие, предлагает после устного собеседования сделать тестовое задание. Как человек, который два года назад делал похожее задание при трудоустройстве, решила разобрать основные ошибки тестировщиков при его выполнении, а также поделиться спецификой наших (и не только) ожиданий в ходе найма.  Цель проведения тестовых заданий понятна: с кандидатом пообщались на собеседовании, примерно поняли его бэкграунд и теоретические знания. Но так ли хорошо он владеет ими на практике? Можно, конечно, попросить его что-то продемонстрировать прямо на встрече, но зачастую волнение, усталость от предшествующего разговора или работа другие причины могут этому помешать.  Другое дело – писать код дома в удобном кресле, с чашкой чая и мурчащим котом на коленях. Конечно, на это нужно будет специально выделить время, но ведь и на устные собеседования оно необходимо.  Однако раз уж задание выполняется в комфортных условиях, то свалить недочеты на излишнее волнение уже не получится. С точки зрения работодателя, требования к качеству выполненного такого задания будут выше. Кандидату же тестовое задание дает представление о том, чем ему придется заниматься на новом месте, какие задачи решать, как они будут ставиться. . Не исключено, что только прочитав требования или даже уже дойдя до конца, он почувствует, что это совершенно не его чашка чая.  Как было сказано выше, цель тестового – продемонстрировать, что кандидат умеет использовать озвученные на собеседовании знания и навыки. Разумеется, весь свой спектр умений проявить не получится, но этого от вас и не ждут.  Хорошо показать знание стандартных тестовых методологий и принципов: проверку граничных значений и классов эквивалентности, атомарность и независимость тестов и другие. Кроме того, может быть полезно уточнить требования к коду у нанимателя: кому-то может быть важнее оптимизация, кому-то – читаемость. Хотя по моему скромному мнению, если мы говорим о тестовых на должность QA, читаемость предпочтительнее. Код будет смотреть незнакомый человек, которому лично объяснить свой подход не получится, не говоря уже о том, что в первую очередь будет оцениваться качество самих тестов. И этому человеку должно быть понятно, что и как в тесте проверяется. Впрочем, читаемость полезна и в повседневной жизни, ведь это позволяет в дальнейшем в любой момент легко вернуться к тесту и что-то при необходимости подправить. В тестовом задании нашего QA отдела предлагается написать тесты для REST API серверного приложения. Спецификация к нему прилагается. API содержит POST, GET и DELETE запросы, манипулирующие с некой сущностью (в задании, конечно, сущность не абстрактная, а из нашей области работы, но ниже в примерах будет присутствовать как entity). Также есть запрос снапшота, который возвращает все неудаленные сущности в их текущем состоянии.  Раньше требовалось написать заодно свою упрощенную реализацию этого приложения и покрывать тестами уже ее, теперь же предоставляется доступ к специальному тестовому серверу, где все уже работает.  Однако независимо от задания есть набор типичных ошибок, которые допускают кандидаты. Разберем их ниже. (Примеры взяты из тестовых заданий кандидатов. Названия некоторых переменных и методов изменены, все остальное сохранено.) Казалось бы, почему про это вообще нужно писать? Но часто кандидаты видят перечень доступных запросов и, конечно, не для всех, но хотя бы для одного из них оставляют лишь одинокий позитивный тест. Способен ли один тест проверить запрос целиком? Очень вряд ли.  Из менее очевидного: часто пропускаемый тест с получением пустого результата в ответ на GET-запрос. Какое-то время назад нам подобные тесты как раз очень пригодились, пока проверяли, не потерялась ли совместимость между проектами. Есть вечное противостояние: «хочу, чтобы тесты были атомарными, и каждый проверял что-то одно» и «не хочу делать сложную и долгую подготовку окружения много раз, сделаю ее один раз и все нужные вещи сразу проверю». Ответа, что из этого лучше, у меня по-прежнему нет, но, например, для проверки REST API в нашем негромоздком тестовом задании сложная подготовка окружения не нужна. Так что можно смело разделить тест, который проверяет а) невалидное создание сущности, б) валидное создание сущности, в) последующий GET-запрос с полной проверкой тела ответа, на три отдельных теста. Пример из тестового задания одного соискателя: Тест отлично разделился бы на четыре теста поменьше, что привело бы к атомарности и лучшей читаемости.  Извиняюсь за тавтологию, но такое тоже часто встречается. Кейс хороший придумали и выполнили, а проверили что-то совершенно не то. Так, например, в тесте на проверку GET-запроса, надо обязательно проверить код и полное тело ответа (иногда еще заголовки, но не в нашем случае). С большой вероятностью часть данных (а в идеале все) из ответа нам известны, и мы можем их все по букве и проверить.  Но, например, в одном из тестовых кандидат сделал следующее: Тест должен был проверить запрос на получение снапшота. Запрос отправляется, ответ записывается в файл, а потом мы проверяем, что полученный ответ является строкой и имеет длину отличную от 0. Возможно, после этого кандидат проверял ответ глазами, но из полученного кода нам это уже никак не узнать.  Также надо быть внимательным с негативными тестами: надо быть уверенным, что тест негативен по какой-то конкретной причине. Например, если мы хотим проверить GET или DELETE с несуществующим id, то этот id должен быть из разрешенного диапазона, иначе получается уже другая ошибка. Или если мы проверяем какое-то невалидное заполнение формы, то лучше ввести некорректное значение только для одного поля, а не для всех сразу. Тест в коде выше поймает ошибочные входные данные, но не даст никакой гарантии, что валидируется каждое из полей, а не только одно.  Часто при проверке запросов опускается последующая проверка состояния хранилища (БД, например): Несмотря на название теста, в нем подразумевалась проверка создания сущности. Вы могли бы сказать, что здесь должен проверяться только код, тут и по названию видно, но про названия тестов поговорим ниже. Придется поверить мне на слово, что отдельного теста на создание не было, а его функцию, по-видимому, выполнял этот. В тесте шлется запрос на создание сущности, проверяется код ответа на запрос, схема ответа, но никакой проверки, что после этого сущность действительно куда-то записалась, нет.  Аналогично с удалением: после того, как мы проверили успешный ответ на запрос, нужно удостовериться, что сущность действительно была удалена. Пожалуй, самая первая из методологий тестирования, приходящих на ум, однако в тестовых заданиях часто отсутствует. Объяснять, что это, вряд ли необходимо, но внимательно прочитайте требования к вводимым данным и проверьте, нет ли граничных значений, которые вы забыли протестировать. Все еще загадочное для меня, но все еще периодически появляющееся в выполненных заданиях явление. Кандидат создает случайный генератор входных данных и передает в тест. Вроде изначальная идея понятна: какие-то из рандомно сгенерированных входных данных могут внезапно отловить какую-то ошибку, да и вообще такое поведение как будто бы ближе к реальному. На другой чаше весов лежит абсолютная непредсказуемость теста. Мы запустили его десять раз, и нам повезло, а на одиннадцатый он вдруг упал. Сколько раз потребуется его перезапустить, чтобы снова это воспроизвести? Неужели и на CI надо запускать тест 11 раз? Или больше? Как точно определить, что мы в итоге проверяем в тесте?  В этом тестовом кандидат генерировал невалидные наборы входных данных, среди которых могли попасться и валидные, в цикле создавал тысячу штук и проверял, что смогли создаться только те из них, кому повезло получить хорошие значения во всех полях.  В некоторых ситуациях подобный подход может быть уместен, но опять же в случае тестового лучше подумать и расписать детерминированные кейсы с детерминированными входными данными и поведением. С одной стороны, в этом ничего плохого нет. Если кандидат обладает большим количеством навыков и знает, как ими блеснуть в тестовом, это круто. Но это не должно быть основной задачей. Один наш кандидат добавил в тестовое и логирование, и потоки, и даже скромный нагрузочный тест (хотя всего этого в задании не требовалось), но, к сожалению, не прошел, так как с полнотой покрытия его тесты не справлялись. Возможно, если бы он сфокусировался сперва на кейсах, а потом уже на демонстрации остальных своих умений и возможностей, сейчас у меня был бы крутой коллега. Это не является ошибкой, скорее, что-то вроде правила хорошего тона. Хорошо читаемый код – это всегда приятно, к тому же сильно упрощает и ускоряет проверку. Поэтому здорово, когда в нем есть комментарии, переменные названы не одной буквой, у аргументов методов есть аннотации, а у assert-ов указано сообщение с ошибкой. А еще когда тест зовут не “test_code_400”, а, например, “test_get_entity_invalid_id”. Тестовое задание – один из трех китов, на которых строится представление о кандидате (помимо резюме и устного собеседования). Поэтому выполнять его спустя рукава не стоит, даже если собеседование прошло блестяще. У нас в Scalable мы смотрим не на конкретное число допущенных или не допущенных ошибок в тестовом задании. Если 80% (условно) из перечисленного выше нет, то в целом неплохо. Куда важнее общее впечатление: Насколько кандидат рационален и логичен – как он строит мысли, как строит кейсы;  Как оформлен код, насколько он читаем, как структурирован;  Умеет ли кандидат думать за рамками ТЗ. Как он уточняет (и делает ли это вообще) задание и конкретизирует требования.  Разумеется, имеет значение и общее владение фундаментальными знаниями по тестированию. Но немаловажный фактор – наличие интереса к тому, чем предстоит заниматься. Тестирование финтех бэкенда: как мы дошли до 20 тыс. тест-кейсов Телеграм-канал Scalable Insights, где мы делимся аналитикой и инсайтами в new fintech  QA