Многозадачность и параллелизм в тестировании |
23.10.2020 00:00 |
Автор: Ноэми Феррера (Noemi Ferrera) На ряд концепций обращается очень много внимания в ходе разработки, но их обычно забывают при тестировании. Так, с моей точки зрения, происходит с многозадачностью и паралеллизмом. Я бы хотела обсудить их важность для тестирования. Параллельный запуск тестов Это одновременное выполнение нескольких тестов на разных машшинах. Иногда это происходит извне (к примеру, в "облаке" – технически это группа реальных компьютеров, которые размещены в нескольких неизвестных локациях). Можно ли одновременно прогонять тесты на одной машине? Технически при наличии нескольких процессоров они могут работать для ваших тестов одновременно, но это не точно. Иногда машины с несколькими процессорами нужно явно указывать при создании кода. В этом случае код будет сложным и зависимым от железа, а это так себе идея. Многозадачность: что это и зачем оно нужно? Вы, возможно, думаете “придержи коней, я запускал тесты параллельно на своей машине, и они отлично работали”. Отвечаю: точно ли вы знаете, что они действительно запускались параллельно и это не иллюзия, созданная вашей машиной? Компьютеры очень здорово имитируют одновременную работу: вы можете перемещать мышь и смотреть видео, и мышь не мешает просмотру. Но это не значит, что все именно так происходит: процессор просто перемещается между ними так быстро, что глаза не успевают это осознать. Многозадачность - это ощущение, что что-то происходит одновременно с чем-то еще. Именно это вы и видите, запуская тесты “параллельно” на своей машине. Хоть эта концепция и может казаться далекой от тестирования, множество приложений разработаны в расчете на многозадачность, и она может вызывать массу ошибок. Следовательно, мы должны быть настороже и пробовать вызвать эти ошибки. Если какую-то ошибку сложно воспроизвести и она кажется случайной, подумайте о том, что она может быть вызвана многозадачностью (или параллелизмом, если в процессе участвует несколько машин). Важность независимых тестов Чтобы добиться параллелизма, надо убедиться, что тесты не будут мешать друг другу. Рассмотрим на примере: Тест 1: “Предмет можно добавить в корзину” - тест добавляет предмет в корзину. Убедиться, что предмет находится в корзине. Тест 2: “Предмет можно удалить из корзины” - тест добавляет предмет в корзину и удаляет его. Убедиться, что корзина пуста. Можете сказать, какие проблемы могут быть вызваны этими тестами при их одновременном запуске? Если они делят общую корзину, то могут начать рандомно падать в зависимости от времени выполнения теста. Очень важно, чтобы тесты предоставляли уникальную ценность, которая не меняется при одинаковых условиях вне зависимости от времени запуска теста. Чтобы улучшить тесты, можно проверить, что из корзины удален конкретный предмет, а не пустоту корзины. Подумайте также, что будет, если параллельно запустятся два одинаковых теста (два человека нажали на прогон). К примеру, рассмотрим выполнение двух тестов, вызванных дважды (1.1 и 1.2 - два запуска одинакового теста 1 из примера выше). Тест 1.1: добавляет предмет. Тест 1.2: добавляет предмет. Тест 1.1: убеждается, что предмет у корзине. Удаляет его. Тест 1.2: убеждается, что предмет в корзине (он добавлялся дважды, поэтому он там есть) и удаляет его. Если с удалением нет проблем (на что должен быть отдельный тест), все должно нормально сработать. Но что, если другой тест - тест 2 - запустится дважды? Тест 2.1: добавляет предмет в корзину. Тест 2.2: добавляет предмет в корзину. Тест 2.1: удаляет предмет. Тест 2.1: проверяет, что предмет удален. Фейл! (он все еще там) Тест 2.2: запускается и проходит.
(Это самый востребованный в 2020 году предмет, и мы только что добавили чересчур много предметов в корзину) В качестве решения можно убедиться в количестве предметов перед их удалением, но даже в этом случае нет гарантий, что другой тест не добавит предмет в корзину сразу после вашей проверки. Тогда можно добавлять уникальные значения предметов в каждом тесте (они могут храниться в базе данных с уникальным ID). Если уникальности нельзя добиться этим способом, возможно, можно создать метод для получения предметов из списка на основании вашего IP и времени запуска, чтобы предметы выбирались случайным образом и было безопаснее (но это все еще не гарантия независимости). Другой способ внедрения уникальности - это использование различных пользователей при запуске, чтобы ваша корзина была уникальна для теста. Однако количество тестовых пользователей может быть ограничено, и может понадобиться способ жонглировать ими между запусками тестов. И, наконец, можно управлять запуском тестов, убеждаясь, что никто не будет запускать этот тест одновременно с вами. Правильное решение сильно зависит от реализации вашего приложения и тест-платформы. Будьте осторожны с методами вроде “initialise” и “cleanup” в своих тестах. Эти методы нужно использовать для распространенных повторяемых операций в тестах - например, инициализации переменных, а не для выполнения таких задач, как удаление предметов из корзины. Зависимости в тестировании Иногда нам может понадобиться разобраться с зависимостями в тестировании. Я не говорю о “всегда запускайте тест 1 перед тестом 2” - это, как правило, очень плохая идея и ее нужно избегать. Но что, если вам нужен способ связать два теста? Например, вы тестируете чат-платформу, и вам нужно проверить вот такую функцию: Друг 1: открывает чат. Говорит “привет”. Друг 2: должен увидеть новый чат с приветом. Отправляет “получено”. Друг 1: видит, что сообщение получено.
В этом случае вам нужно управлять всем изнутри теста и убедиться, что если вы прогоните этот тест дважды, он не помешает сам себе. Это можно сделать множеством способов, но об этом в другой раз. |