В статье хочу поделиться кейсом, с которым столкнулся на одном из проектов. И расскажу о своем варианте его решения.
Стояла задача автоматизации регресса для сервиса миграции из системы Jira во внутреннюю систему «Яга».
Если упростить, то типичный тест-кейс представлял из себя следующие шаги:
-
Создание тестового проекта в Jira
-
Обогащение проекта данными
-
Миграция тестового проекта в «Яга»
-
Проверка успешности миграции
Давайте детальнее разберем реализацию каждого пункта.
1. Создание тестового проекта в Jira
Первая проблема, которую я так и не смог до конца побороть — это создание проекта в Jira.
У нашей версии нет возможности создать полностью индивидуальный проект с нуля через api. Начинаются сложности с тем, чтобы создать workflow и привязать его к проекту.
В облачной версии большая часть этих сложностей уже устранена, но увы, у нас серверный вариант.
В сложившейся ситуации наименее затратным решением оказалось создать шаблон проекта, используя недокументированный endpoint shared configuration. Далее на основании этого шаблона с уже описанным бизнес процессом можно легко создавать другие проекты.
Минусом такого решения является зависимость тестов от тестовых данных на стенде. Если по какой-то причине шаблонный проект исчезнет или будет модифицирован, то тесты упадут. Но в нашем случае риск минимален и оправдан.
2. Обогащение проекта данными
Тут с api все хорошо.
Можно добавлять задачи, подзадачи, создавать различные связи между ними, двигать по разным статусам.
Сами методы обогащения проекта выглядят примерно вот так:
public void setupEnv_JAGA4826() { log.info("------подготовка JAGA4826"); jira.createIssue(jiraClient, jiraProjectId, adminLogin); data.put("JAGA4826_jira_project_id", jiraProjectId); }
3. Миграция тестового проекта в «Яга»
Теперь основная часть. Дело в том, что миграция любого проекта регресса длится в среднем от 2 до 10 минут. Учитывая, что каждый тест-кейс предполагает миграцию проекта, то времени на прогон сотни автотестов уйдет около 10 часов.
Как найти выход из этой ситуации?
Мы придумали самое простое решение:
-
Создаем проект на базе шаблона
-
После добавляем в него столько данных, сколько необходимо для каждого теста.
-
Мигрируем проект из Jira в «Яга».
-
После миграции запускаются автотесты.
Теперь у нас уходит порядка 15-20 минут на миграцию проекта и по несколько секунд на каждый автотест.
Как это реализовано на практике?
Наш основной стек — это Java, Junit5, RestAssured, Allure.
Проект может быть запущен со всеми тестами или с тестами с определенным тегом (например Smoke) или вовсе с 1 единственным тестом для отладки.
Чтобы каждый раз не создавать проект со всеми возможными тестовыми данными в самом начале анализируем тестовый план.
1. Создаем класс.
public class TestPlanListener implements TestExecutionListener{...}
Внутри которого переопределяем метод.
@Override public void testPlanExecutionStarted(TestPlan testPlan) {...}
2. Из тест-плана извлекаем весь список тэгов, которые есть в тестовом классе.
Тэги с предопределенным префиксом и есть наша цель. Каждый класс, который требует добавления тестовых данных в проект, содержит подобный тэг.
Полный текст класса тут
import org.junit.platform.engine.TestTag; import org.junit.platform.engine.support.descriptor.MethodSource; import org.junit.platform.launcher.TestExecutionListener; import org.junit.platform.launcher.TestIdentifier; import org.junit.platform.launcher.TestPlan; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import ru.rtkit.converter.environment.TestEnv; import java.util.List; import java.util.Optional; import java.util.Set; public class TestPlanListener implements TestExecutionListener { private static final Logger log = LoggerFactory.getLogger(TestPlanListener.class); public static final String ENV_TAG_PREFIX = "setupEnv_"; @Override public void testPlanExecutionStarted(TestPlan testPlan) { TestExecutionListener.super.testPlanExecutionStarted(testPlan); log.info("Подготовка тестового окружения"); Set<TestIdentifier> roots = testPlan.getRoots(); TestIdentifier root = getChildContainer(roots).get(0); Set<TestIdentifier> children = testPlan.getChildren(root.getUniqueIdObject()); List<TestIdentifier> container = getChildContainer(children); List<String> tags = getTestTags(container); TestEnv.setup(tags); log.info("Начало выполнения тестов"); } private static List<String> getTestTags(List<TestIdentifier> containers) { return containers.stream() .flatMap(container -> container.getTags() .stream() .map(TestTag::getName) .filter(tag -> tag.startsWith(ENV_TAG_PREFIX)) ) .toList(); } private static List<MethodSource> getMethodSources(TestPlan testPlan, TestIdentifier container) { return testPlan.getChildren(container.getUniqueIdObject()) .stream() .map(TestIdentifier::getSource) .filter(Optional::isPresent) .map(source -> (MethodSource) source.get()) .toList(); } private List<TestIdentifier> getChildContainer(Set<TestIdentifier> testIdentifiers) { List<TestIdentifier> containers = testIdentifiers .stream() .filter(TestIdentifier::isContainer) .toList(); if (containers.isEmpty()) { throw new RuntimeException("Не найден контейнер в тест-плане"); } return containers; } @Override public void testPlanExecutionFinished(TestPlan testPlan) { TestExecutionListener.super.testPlanExecutionFinished(testPlan); log.info("Окончание выполнения тестов"); log.info("Удаление тестового окружения"); } }
3. Список тэгов передаем в метод, который занимается формированием тестового окружения.
4. Для каждого тэга вызываем метод обогащения тестовых данных.
public static void setupEnvByClassTag(String methodName) { try { TestEnv.class .getMethod(methodName) .invoke(new TestEnv()); } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) { e.printStackTrace(); } }
4. Проверка успешности миграции
Все этапы до этого можно назвать прекондицией. Теперь рассмотрим, как выглядят сами автотесты.
Здесь все достаточно тривиально.
Тестовый класс выглядит примерно так:
import io.qameta.allure.*; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Tag; import org.junit.jupiter.api.Test; import ru.rtkit.converter.environment.TestEnv; import ru.rtkit.converter.helpers.constants.Status; import ru.rtkit.converter.helpers.constants.Tags; import ru.rtkit.converter.helpers.jaga.JagaHelper; import ru.rtkit.converter.tests.BaseTest; import static ru.rtkit.converter.helpers.AllureAssertions.*; @DisplayName("Системное условие") @Tag("setupEnv_JAGA4826") public class UserInGroupConditionTests extends BaseTest { String jagaProjectId; String jiraProjectId; String jagaTaskId; String targetStatusId; String actualTaskStatusId; private JagaHelper jaga; @BeforeEach void beforeEach() { jagaProjectId = TestEnv.data.get("jaga_project_id"); jiraProjectId = TestEnv.data.get("JAGA4826_jira_project_id"); jaga = new JagaHelper(jagaAdminClient, jagaUserClient, jagaProjectId, jiraProjectId); jagaTaskId = jaga.asAdmin().getDefaultTaskId(); assertNotNull(jagaTaskId, "Не удалось получить идентификатор задачи с полем 'UserInGroupCondition'"); targetStatusId = jaga.asAdmin().getStatusId(Status.USER_IN_GROUP); assertNotNull(targetStatusId, "Не удалось получить идентификатор статуса " + Status.USER_IN_GROUP); } @Test @TmsLink("JAGA-T1921") @DisplayName("Миграция условия UserInGroupCondition") @Description("Миграция условия UserInGroupCondition") @Story("JAGA-4826") @Feature("JAGA-4528") @Epic("JAGA-3793") @Tag(Tags.REGRESS) void migrateUserInGroupConditionTest() { jaga.asAdmin().updateTaskStatus(200, jagaTaskId, targetStatusId); actualTaskStatusId = jaga.asAdmin().getCurrentTaskStatus(jagaTaskId); assertEquals(targetStatusId, actualTaskStatusId, "Статус задачи НЕ изменился"); } }
Заключение
Всю нехитрую логику можно уместить на этой схеме.
Скорее всего, было бы правильнее хранить метод обогащения проекта тестовыми данными в самом тестовом классе, но показалось, что удобнее собрать все в одном месте.
Возможно, кому-то этот пример принесет немного пользы.
ссылка на оригинал статьи https://habr.com/ru/articles/924902/
Добавить комментарий