This Talk will discuss how and why to write your plugins for IntelliJ IDEA.
Consider some of problems that were solved with the help of plugins on an example.
Interaction with external systems when writing tests. Creating new entities in the external system and getting some data.
Mass refactoring of a large number of tests
Automation Functional Testing in Agile ProjectsAndrey Rebrov
Об автоматических тестах писал ещё Сам Кент Бек. Ну, а автоматические функциональные тесты — это вообще лакомый кусок для современных agile методик разработки ПО. Вместе с участниками кемпа мы узнаем, с какой стороны подходить к процессу автоматизации тестирования в целом. Кроме того, мы создадим проект автотестирования с использованием одного из самых популярных продуктов для тестирования веб-приложений — Selenium 2.
TК°Conf. 10 проблем автоматизации UI и их решение с помощью JDI. Роман Иовлев.TKConf
Автоматизация тестирования является важной и не неотъемлемой частью разработки современного ПО, но без правильного подхода не редко случается, что написание автотестов занимает слишком много времени, а их поддержка может требовать больше затрат чем просто ручная регрессия. Почему же так происходит и как этого избежать? В этой презентации, базируясь на своем опыте работы во множестве проектов, я хочу рассказать об основных ошибках и проблемах, с которыми приходится сталкиваться автоматизаторам и что нужно сделать чтобы их избежать (на примере фреймворка для автоматизации JDI)
Automation Functional Testing in Agile ProjectsAndrey Rebrov
Об автоматических тестах писал ещё Сам Кент Бек. Ну, а автоматические функциональные тесты — это вообще лакомый кусок для современных agile методик разработки ПО. Вместе с участниками кемпа мы узнаем, с какой стороны подходить к процессу автоматизации тестирования в целом. Кроме того, мы создадим проект автотестирования с использованием одного из самых популярных продуктов для тестирования веб-приложений — Selenium 2.
TК°Conf. 10 проблем автоматизации UI и их решение с помощью JDI. Роман Иовлев.TKConf
Автоматизация тестирования является важной и не неотъемлемой частью разработки современного ПО, но без правильного подхода не редко случается, что написание автотестов занимает слишком много времени, а их поддержка может требовать больше затрат чем просто ручная регрессия. Почему же так происходит и как этого избежать? В этой презентации, базируясь на своем опыте работы во множестве проектов, я хочу рассказать об основных ошибках и проблемах, с которыми приходится сталкиваться автоматизаторам и что нужно сделать чтобы их избежать (на примере фреймворка для автоматизации JDI)
SECON'2016. Иовлев Роман, JDI is UI Automation FutureSECON
Хочешь узнать как можно получать удовольствие от автоматических тестов? Как писать сами тесты не тратя время на многочисленные Хелперы и заплатки? И при этом получить действительно качественные понятные тесты с детальными логами и возможностью быстрого рефакторинга? Ты хочешь иметь тесты написанные в едином стиле не только для Web, но и мобильных устройств и даже десктоп приложений? Приходи и мы расскажем как наша новая разработка JDI поможет тебе стать настоящим Джедаем в автоматизации!
У вас древний проект? Все зовут его «Legacy», а вас «неудачник»? Возможно они даже смеются над вами.
Давайте взглянем на ситуацию с другого ракурса. Все (все, Карл!) успешные проекты рано или поздно превращаются в Legacy-проекты.
Я затрону тему Legacy не просто как явление, а как возможность быть постоянно в тренде, прослыть супер-спецом (даже если ты знаешь всего два фреймворка), сделать карьеру, как делать, то что ты хочешь, а не то что тебя просят. Ладно, ладно, я наврал про два фреймворка, но все остальное чистая правда. Я покажу, что вы можете творить, имея правильный подход к Legacy коду.
Суть в том, что Legacy — это не грустно/уныло/немодно, это просто/клево/весело, если с умом подойти к задаче!
Бодрящий микс из Selenium и TestNG- регрессионное тестирование руками разрабо...Andrey Rebrov
Как-то так происходит, что “на 10 девчонок по статистике 9 ребят”, а точнее на группу из 5-7 разработчиков – 1 тестировщик. Или его нет совсем. Так что очень часто приходится и код писать, и тестировать, а дата релиза все ближе и ближе.
В тех случаях, когда мы пишем веб-приложение, помочь в нашей нелегкой судьбе может бодрящий микс из Selenium и TestNG... Как это сделали мы, какие потом получили выводы и результаты — все это я и хочу рассказать и показать
Мир мобильных телефонов очень сильно изменил нашу жизнь. В наше время невозможно представить современного человека, без этого чудо устройства. На рынке появляется все больше устройств и приложений. И чтобы удобнее пользоваться этими приложениями пользователи выбирают “умные” телефоны, или как их еще принято называть смартфоны. В своем докладе я хочу поделиться своим опытом автоматизации приложений под Android и iOS. Я расскажу о том, какие инструменты автоматизации я использовал. Поговорим о недостатках этих инструментов и какие из них стоит использовать у себя на проекте.
QA Fest 2017. Яна Кокряшкина. Интеграция автоматизированных тестов с инструме...QAFest
Как автоматически поставить тест кейсу статус "Pass", создать новый или зактрыть проверенный баг? Во время презентации расскажу как интегрировать автоматизированные тесты с инструментами для тестирования. Покажу рельные примеры совместной работы автоматизированных тестов для веб сайта, написаных на Java или Python, с YouTrack, TestRail и EasyQA.
Atlas – Next Generation of Page Object, which uses the interfaces instead of classes, Page Object tree structure, embedded waits and clear assertions. In talk, I will tell about the core functionality of the framework, the developer, which I am and show it extension points.
Разработка крупного Standalone проекта на юнити: улучшаем производительностьВадим Воробьев
Презентация к докладу на DevGamm 2015, Минск.
В докладе рассказывлось о технических тонкостях оптимизации под ПК в Unity на примере The Godlike и приводились истории разработки. Как использовать кодогенерацию, что может профайлер Unity, как правильно работать с UI и почему не стоит связываться с LINQ.
JavaScript - мой основной язык программирования, но два года я была в “Java-JavaScript” иммиграции, а последние полгода провела со Swift. Теперь, возвращаясь к JavaScript, я часто сравниваю, как там у “них”.
Этот доклад о том, чего мне не хватает в JavaScript, и почему JavaScript разработчику следует путешествовать в другие языки.
SECON'2016. Иовлев Роман, JDI is UI Automation FutureSECON
Хочешь узнать как можно получать удовольствие от автоматических тестов? Как писать сами тесты не тратя время на многочисленные Хелперы и заплатки? И при этом получить действительно качественные понятные тесты с детальными логами и возможностью быстрого рефакторинга? Ты хочешь иметь тесты написанные в едином стиле не только для Web, но и мобильных устройств и даже десктоп приложений? Приходи и мы расскажем как наша новая разработка JDI поможет тебе стать настоящим Джедаем в автоматизации!
У вас древний проект? Все зовут его «Legacy», а вас «неудачник»? Возможно они даже смеются над вами.
Давайте взглянем на ситуацию с другого ракурса. Все (все, Карл!) успешные проекты рано или поздно превращаются в Legacy-проекты.
Я затрону тему Legacy не просто как явление, а как возможность быть постоянно в тренде, прослыть супер-спецом (даже если ты знаешь всего два фреймворка), сделать карьеру, как делать, то что ты хочешь, а не то что тебя просят. Ладно, ладно, я наврал про два фреймворка, но все остальное чистая правда. Я покажу, что вы можете творить, имея правильный подход к Legacy коду.
Суть в том, что Legacy — это не грустно/уныло/немодно, это просто/клево/весело, если с умом подойти к задаче!
Бодрящий микс из Selenium и TestNG- регрессионное тестирование руками разрабо...Andrey Rebrov
Как-то так происходит, что “на 10 девчонок по статистике 9 ребят”, а точнее на группу из 5-7 разработчиков – 1 тестировщик. Или его нет совсем. Так что очень часто приходится и код писать, и тестировать, а дата релиза все ближе и ближе.
В тех случаях, когда мы пишем веб-приложение, помочь в нашей нелегкой судьбе может бодрящий микс из Selenium и TestNG... Как это сделали мы, какие потом получили выводы и результаты — все это я и хочу рассказать и показать
Мир мобильных телефонов очень сильно изменил нашу жизнь. В наше время невозможно представить современного человека, без этого чудо устройства. На рынке появляется все больше устройств и приложений. И чтобы удобнее пользоваться этими приложениями пользователи выбирают “умные” телефоны, или как их еще принято называть смартфоны. В своем докладе я хочу поделиться своим опытом автоматизации приложений под Android и iOS. Я расскажу о том, какие инструменты автоматизации я использовал. Поговорим о недостатках этих инструментов и какие из них стоит использовать у себя на проекте.
QA Fest 2017. Яна Кокряшкина. Интеграция автоматизированных тестов с инструме...QAFest
Как автоматически поставить тест кейсу статус "Pass", создать новый или зактрыть проверенный баг? Во время презентации расскажу как интегрировать автоматизированные тесты с инструментами для тестирования. Покажу рельные примеры совместной работы автоматизированных тестов для веб сайта, написаных на Java или Python, с YouTrack, TestRail и EasyQA.
Atlas – Next Generation of Page Object, which uses the interfaces instead of classes, Page Object tree structure, embedded waits and clear assertions. In talk, I will tell about the core functionality of the framework, the developer, which I am and show it extension points.
Разработка крупного Standalone проекта на юнити: улучшаем производительностьВадим Воробьев
Презентация к докладу на DevGamm 2015, Минск.
В докладе рассказывлось о технических тонкостях оптимизации под ПК в Unity на примере The Godlike и приводились истории разработки. Как использовать кодогенерацию, что может профайлер Unity, как правильно работать с UI и почему не стоит связываться с LINQ.
JavaScript - мой основной язык программирования, но два года я была в “Java-JavaScript” иммиграции, а последние полгода провела со Swift. Теперь, возвращаясь к JavaScript, я часто сравниваю, как там у “них”.
Этот доклад о том, чего мне не хватает в JavaScript, и почему JavaScript разработчику следует путешествовать в другие языки.
Илья Шаляпин, Евгений Генералов: Разработка через тестирование в Python и Djn...it-people
Большинство примеров тестов в книгах, семинарах и презентациях упрощены настолько, что их невозможно применить в реальных проектах. Из-за такого упрощения, сначала получаешь заряд мотивации, но столкнувшись с суровой действительностью быстро бросаешь написание тестов. Мы решили исправить этот пробел, показав тестирование на реальных примерах из нашей практики. Мы расскажем о тестировании баз данных, сетевых взаимодействий и веб-форм. Также расскажем об инструментах, которые мы используем для тестирования.
Сергей Константинов — Что интересного готовит нам W3CYandex
2014 год обещает нам множество интересных нововведений. Помимо новинок в HTML5, нас ждут глобальные изменения в самой веб-платформе. Promises и модули — революция в стандартах разработки стандартов. Service Workers — новый подход к решению проблемы офлайновых веб-приложений. @@create — отнаследуйся от HTMLElement! Обо всём этом и пойдёт речь в докладе.
Similar to How IntelliJ IDEA plugin can help you in QA Automation (20)
Building functional Quality Gates with ReportPortalDmitriy Gumeniuk
Presented at SeleniumConf 2023, this talk explores the experience of building Quality Gates using ReportPortal.io for a test regression suite with 200,000 test cases. The discussion highlights the distinctions between functional and non-functional quality gates, explaining why Sonarqube's Quality Gates may be insufficient. It also outlines how to break down the regression structure to organize execution sequences controlled by quality gate checks. These checks are based on various factors, including functional application aspects, test failure types, test case priorities, tested components, user flows, and more—providing a comprehensive approach to ensuring software quality.
Speaker: Dmitriy Gumeniuk, CEO ReportPortal.io,
Head of Testing Products at EPAM Systems.
The talk on youtube: https://www.youtube.com/watch?v=At5MEWqf_TI
Self healing test automation with Healenium and Minimization of regression su...Dmitriy Gumeniuk
The document discusses two tools: Healenium and Drill4J. Healenium is a self-healing automation tool that uses machine learning algorithms to dynamically update locators when web pages change, reducing test failures. It works by comparing DOM trees to generate new locators. Drill4J maps test cases to code modules to help identify gaps in test coverage and code modified by a given test case.
Test Gap Analysis and regression minimization with Drill4j. Observability on ...Dmitriy Gumeniuk
Test Gap Analysis is the process of identifying these gaps where new code has been deployed but hasn’t been tested yet. However, often your testing department does not know which parts of code have been changed by the developers. As a result, testers run some unnecessary tests while other crucial tests are overlooked.
With Test Gap Analysis we can find gaps in tests and help you avoid errors made due to recent, untested changes. In doing so, you can optimize the interface between developers and testers and avoid hotfixes after the system’s release.
With this talk Dmitriy will share and unveil new Open Sourced tool Drill4J, describe capabilities of Test-to-Code mapping and how you can minimize your regression time by identifying subset of tests, which should be run, which code have been changed and which changes are not tested after full testing cycle.
The development of Selenium 3 is officially discontinued. The next major version of Selenium 4 is being prepared for release. New commands that have been recently added to the W3C WebDriver standard will appear. A lot of legacy code will be removed, including the driver for “old” versions of Firefox. But the main changes will take place in Selenium Server and Selenium Grid. In short, the server will be completely redesigned, the new implementation is written from scratch. Yes, communication protocols will remain old, but the internal device will change beyond recognition. In particular, if earlier Selenium Grid consisted of two types of nodes (hub and end nodes), the new version will have four types of nodes. In my report, I will try to explain why we changed everything, who will get better from this, what will be the possibilities for customizing the grid in the new version and how to migrate from the old version to the new one.
I will share my experience of SDLC enablement on enterprise level. Uncover pitfalls and gotchas about building of developer friendly CI enabled service using industry standard static and dynamic scanning tools, CI platforms, ReportPortal, Carrier platform and Jira integration service.
This talk will share how to migrate your application to the cloud, assuming serverless infrastructure. Talk will share principals of service model usage, generic cloud usage, extended with real examples
Building a self-service marketplace for Test Data (Dzmitry Humianiuk, Belarus)Dmitriy Gumeniuk
In a world of testing pipelines, when we need to run tests against every code change, the problem of sustainable, comprehensive and variative data starts to arise. Testing data, which in the maximum approximation can repeat all the conditions available in the production, in order to cover as much as possible those conditions that are critical for business and have a clear presence in the production. The subject of test data management is quite extensive, so we will try to understand it in order. Starting from the stage of obtaining secure production data, to virtualization and synthetic generation. And let’s look at examples of how to prepare data production for test environments, and analyze the example of an open-source application, as it can be implemented for your project.
Powerful tools give a lot room for improvements. In order to make it valuable for you, I define your way of configuration. This talk will represent use cases of ReportPortal and the most beneficial configurations of usage. Based on real project examples, with collected metrics and efficiency improvement for them
Applicabilitity of Machine Learning in Test Automation @ Delex Conf 2018, MinskDmitriy Gumeniuk
This document discusses the applicability of machine learning and neural networks in test automation. It describes how ML and NN are currently used for log analysis and test data generation. It then outlines several potential uses of ML/NN in test automation, including defect prediction, defect classification, test coverage optimization, and test case generation/scriptless automation. The document concludes by discussing challenges with classifying failed logs and the potential for neural networks to address this problem.
ReportPortal.io - how to make machine learning categorize your test failsDmitriy Gumeniuk
Introduction into kNN algorithm and how it was used in ReportPortal to analyze and categorize new fails, based on previous runs and analysis. Machine Learning uses previously indexed fail patterns, as a training set, for categorization of new items.
Describes method, toolset and how you can build it
35. Точка входа в Idea Plugin
public class AnAction {
@Override
public void actionPerformed(AnActionEvent event) {
//MAGIC here
}
}
36. public class FirstAction extends AnAction {
@Override
public void actionPerformed(AnActionEvent e) {
Project project = e.getProject();
Editor editor = e.getRequiredData(CommonDataKeys.EDITOR);
PsiElement psiElement = e.getData(PSI_ELEMENT);
String name = ((PsiClass)psiElement).getQualifiedName();
showDialog(cName);
}
}
Основа всего PsiElement
37. public class Steps {
@Step("Open Wrike login page")
public void openWrikeLogin() { ... }
@Step("Open inbox")
public void openInbox() { ... }
...
}
PsiClass - работа с классом
38. PsiMethod - работа с методами
public class Steps {
@Step("Open Wrike login page")
public void openWrikeLogin() { ... }
@Step("Open inbox")
public void openInbox() { ... }
...
}
39. PsiAnnotation - аннотации
public class Steps {
@Step("Open Wrike login page")
public void openWrikeLogin() { ... }
@Step("Open inbox")
public void openInbox() { ... }
...
}
40. public class FirstAction extends AnAction {
@Override
public void actionPerformed(AnActionEvent e) {
PsiElement psiElement = e.getData(PSI_ELEMENT);
PsiClass psiClass = ((PsiClass)psiElement);
String name = psiClass.getQualifiedName();
showDialog(name);
}
}
Выведем Qualified Name
52. Рассмотрим обычный тест
public class LoginTest {
@Before()
public void prepare() { ... }
@Test
@Category({Firefox.class, Smoke.class, Login.class})
@DisplayName("Check login")
public void loginWithCorrectPassword() { ... }
53. Категории автотеста
public class LoginTest {
@Before()
public void prepare() { ... }
@Test
@Category({Firefox.class, Smoke.class, Login.class})
@DisplayName("Check login")
public void loginWithCorrectPassword() { ... }
54. На самом деле их много
public class LoginTest {
@Before()
public void prepare() { ... }
@Test
@Category({Firefox.class, Smoke.class, Login.class,
Workspace.class, IE.class, Safari.class
...})
@DisplayName("Check login")
public void loginWithCorrectPassword() { ... }
55. Технические категории
public class LoginTest {
@Before()
public void prepare() { ... }
@Test
@Category({Firefox.class, Smoke.class, Login.class})
@DisplayName("Check login")
public void loginWithCorrectPassword() { ... }
56. Продуктовые категории
public class LoginTest {
@Before()
public void prepare() { ... }
@Test
@Category({Firefox.class, Smoke.class, Login.class})
@DisplayName("Check login")
public void loginWithCorrectPassword() { ... }
57. Нужно поменять разметку
public class LoginTest {
@Before()
public void prepare() { ... }
@Test
@Category({Firefox.class, Smoke.class, Login.class})
@DisplayName("Check login")
public void loginWithCorrectPassword() { ... }
58. Добавить продуктовые фичи
public class LoginTest {
@Before()
public void prepare() { ... }
@Test
@Category({Firefox.class, Smoke.class, Login.class})
@Feature("Login")
@DisplayName("Check login")
public void loginWithCorrectPassword() { ... }
59. Добавить технические типы
public class LoginTest {
@Before()
public void prepare() { ... }
@Test
@Category({Firefox.class, Smoke.class, Login.class})
@Feature("Login")
@Types({@Type("Firefox"), @Type("Smoke")})
@DisplayName("Check login")
public void loginWithCorrectPassword() { ... }
60. Удалить ненужные категории
public class LoginTest {
@Before()
public void prepare() { ... }
@Test
@Feature("Login")
@Types({@Type("Firefox"), @Type("Smoke")})
@DisplayName("Check login")
public void loginWithCorrectPassword() { ... }
63. ReplaceCategoryAction
public class ReplaceCategoryAction extends AnAction {
@Override
public void actionPerformed(AnActionEvent event) {
PsiElement element = event.getData(PSI_ELEMENT)
if (element instance of PsiClass) {
replaceCategory((PsiClass)element)
}
}
}
64. Получили PsiClass
public class LoginTest {
@Before()
public void prepare() { ... }
@Test
@Category({Firefox.class, Smoke.class, Login.class})
@DisplayName("Check login")
public void loginWithCorrectPassword() { ... }
}
65. Берем все методы класса
private void replaceCategory(PsiClass psiClass) {
Arrays.stream(psiClass.getMethods())
.filter(m -> m.hasAnnotation("...Test"))
.filter(m -> m.hasAnnotation("...Category"))
.forEach(this::replaceCategory);
}
66. public class LoginTest {
@Before()
public void prepare() { ... }
@Test
@Category({Firefox.class, Smoke.class, Login.class})
@DisplayName("Check login")
public void loginWithCorrectPassword() { ... }
}
Получили все методы класса
68. Получили тестовый метод
public class LoginTest {
@Before()
public void prepare() { ... }
@Test
@Category({Firefox.class, Smoke.class, Login.class})
@DisplayName("Check login")
public void loginWithCorrectPassword() { ... }
}
70. public class LoginTest {
@Before()
public void prepare() { ... }
@Test
@Category({Firefox.class, Smoke.class, Login.class})
@DisplayName("Check login")
public void loginWithCorrectPassword() { ... }
Получили текст @Category
75. Добавили с полным путем
public class LoginTest {
@Before()
public void prepare() { ... }
@io.qameta.allure.Feature("Login")
@Test
@Category({Firefox.class, Smoke.class, Login.class})
@DisplayName("Check login")
public void loginWithCorrectPassword() { ... }
}
91. ReplaceAllCategoryAction
public class ReplaceAllCategoryAction extends AnAction {
@Override
public void actionPerformed(AnActionEvent e) {
project = e.getProject();
AllClassesGetter.processJavaClasses(
new PlainPrefixMatcher(""),
project,
GlobalSearchScope.allScope(project),
processor);
}
}
92. Начинается с "Test"
public class ReplaceAllCategoryAction extends AnAction {
@Override
public void actionPerformed(AnActionEvent e) {
project = e.getProject();
AllClassesGetter.processJavaClasses(
new PlainPrefixMatcher("Test"),
project,
GlobalSearchScope.allScope(project),
processor);
}
}
93. Обходим все классы
public class ReplaceAllCategoryAction extends AnAction {
@Override
public void actionPerformed(AnActionEvent e) {
project = e.getProject();
AllClassesGetter.processJavaClasses(
new PlainPrefixMatcher(""),
project,
GlobalSearchScope.allScope(project),
processor);
}
}
94. Указываем проект
public class ReplaceAllCategoryAction extends AnAction {
@Override
public void actionPerformed(AnActionEvent e) {
project = e.getProject();
AllClassesGetter.processJavaClasses(
new PlainPrefixMatcher(""),
project,
GlobalSearchScope.allScope(project),
processor);
}
}
95. Скоуп поиска
public class ReplaceAllCategoryAction extends AnAction {
@Override
public void actionPerformed(AnActionEvent e) {
project = e.getProject();
AllClassesGetter.processJavaClasses(
new PlainPrefixMatcher(""),
project,
GlobalSearchScope.allScope(project),
processor);
}
}
96. Логика обработки
public class ReplaceAllCategoryAction extends AnAction {
@Override
public void actionPerformed(AnActionEvent e) {
project = e.getProject();
AllClassesGetter.processJavaClasses(
new PlainPrefixMatcher(""),
project,
GlobalSearchScope.allScope(project),
processor);
}
}
105. public class AddFavoritesAfterNoteTest {
@Test
@DisplayName("Добавление в избранное после создания заметки")
public void shouldAddToFavoriteAfterNodeTest() { ... }
@Test
@DisplayName("Удаление из избранного после удаления заметки")
public void shouldDeleteToFavoriteAfterNodeTest() { ... }
}
Возьмем название теста
107. Нужно расставить ссылки
public class AddFavoritesAfterNoteTest {
@Test
@TmsLink("AE-5")
@DisplayName("Добавление в избранное после создания заметки")
public void shouldAddToFavoriteAfterNodeTest() { ... }
@Test
@TmsLink("AE-4")
@DisplayName("Удаление из избранного после удаления заметки")
public void shouldDeleteToFavoriteAfterNodeTest() { ... }
}
111. Работаем только с классами
public class JiraKeyImportAction extends AnAction {
@Override
public void actionPerformed(AnActionEvent event) {
PsiElement element = event.getData(PSI_ELEMENT)
if (element instance of PsiClass) {
addTmsLinkToClassMethods((PsiClass)element)
}
}
}
112. Выбрали класс для апдейта
public class AddFavoritesAfterNoteTest {
@Test
@DisplayName("Добавление в избранное после создания заметки")
public void shouldAddToFavoriteAfterNodeTest() { ... }
@Test
@DisplayName("Удаление из избранного после удаления заметки")
public void shouldDeleteToFavoriteAfterNodeTest() { ... }
private void utilityMethod() { ... }
}
113. public class JiraKeyImportAction extends AnAction {
void addTmsLinkToClassMethods(PsiClass testClass) {
Arrays.stream(testClass.getMethods())
.filter(m -> m.hasAnnotation("org..Test"))
.filter(m -> m.hasAnnotation("org..DisplayName"))
.forEach(this::addTmsLinkToMethod)
}
}
Получаем все методы класса
114. public class JiraKeyImportAction extends AnAction {
void addTmsLinkToClassMethods(PsiClass testClass) {
Arrays.stream(testClass.getMethods())
.filter(m -> m.hasAnnotation("org..Test"))
.filter(m -> m.hasAnnotation("org..DisplayName"))
.forEach(this::addTmsLinkToMethod)
}
}
Фильтруем тестовые методы
115. Выбрали методы для апдейта
public class AddFavoritesAfterNoteTest {
@Test
@DisplayName("Добавление в избранное после создания заметки")
public void shouldAddToFavoriteAfterNodeTest() { ... }
@Test
@DisplayName("Удаление из избранного после удаления заметки")
public void shouldDeleteToFavoriteAfterNodeTest() { ... }
private void utilityMethod() { ... }
}
116. public class JiraKeyImportAction extends AnAction {
void addTmsLinkToMethod(PsiMethod method) {
PsiAnnotatation nameAnnotation =
method.getAnnotation("org..DisplayName");
String text = name
.findDeclaredAttributeValue("value").getText()
String key = jiraClient.findByText(text);
addTmsLinkToMethod(testMethod, key);
}
}
Берем аннотацию DisplayName
117. Нашли аннотацию с именем
public class AddFavoritesAfterNoteTest {
@Test
@DisplayName("Добавление в избранное после создания заметки")
public void shouldAddToFavoriteAfterNodeTest() { ... }
@Test
@DisplayName("Удаление из избранного после удаления заметки")
public void shouldDeleteToFavoriteAfterNodeTest() { ... }
private void utilityMethod() { ... }
}
118. public class JiraKeyImportAction extends AnAction {
void addTmsLinkToMethod(PsiMethod testMethod) {
PsiAnnotatation name =
method.getAnnotation("org..DisplayName");
String text = name
.findDeclaredAttributeValue("value").getText()
String key = jiraClient.findByText(text);
addTmsLinkToMethod(testMethod, key);
}
}
Берем текст DisplayName
119. Тест для поиска в Jira
public class AddFavoritesAfterNoteTest {
@Test
@DisplayName("Добавление в избранное после создания заметки")
public void shouldAddToFavoriteAfterNodeTest() { ... }
@Test
@DisplayName("Удаление из избранного после удаления заметки")
public void shouldDeleteToFavoriteAfterNodeTest() { ... }
private void utilityMethod() { ... }
}
120. public class JiraKeyImportAction extends AnAction {
void addTmsLinkToMethod(PsiMethod testMethod) {
PsiAnnotatation name =
method.getAnnotation("org..DisplayName");
String text = name
.findDeclaredAttributeValue("value").getText()
String key = jiraClient.findByText(text);
addTmsLinkToMethod(testMethod, key);
}
}
Ищем Issue по тексту в Jira
123. public class JiraKeyImportAction extends AnAction {
void addTmsLinkToMethod(PsiMethod testMethod) {
PsiAnnotatation name =
method.getAnnotation("org..DisplayName");
String text = name
.findDeclaredAttributeValue("value").getText()
String key = jiraClient.findByText(text);
addTmsLinkToMethod(testMethod, key);
}
}
Добавляем аннотацию в код
124. public class JiraKeyImportAction extends AnAction {
void addTmsLinkToMethod(PsiMethod method,String key){
String tmsLinksAnnotationText =
"@io..TmsLink("" + key + "")";
PsiAnnotation tmsLink =
method.addAnnotation(tmsLinkAnnotationText);
JavaCodeStyleManager.getInstance(project)
.shortenClassReferences(tmsLink);
}
}
Формируем текст аннотации
126. Добавили аннотацию
public class AddFavoritesAfterNoteTest {
@Test
@io.qameta.allure.TmsLink("AE-5")
@DisplayName("Добавление в избранное после создания заметки")
public void shouldAddToFavoriteAfterNodeTest() { ... }
@Test
@DisplayName("Удаление из избранного после удаления заметки")
public void shouldDeleteToFavoriteAfterNodeTest() { ... }
}
127. public class JiraKeyImportAction extends AnAction {
void addTmsLinkToMethod(PsiMethod method,String key){
String tmsLinksAnnotationText =
"@io..TmsLink("" + key + "")";
PsiAnnotation tmsLink =
method.addAnnotation(tmsLinkAnnotationText);
JavaCodeStyleManager.getInstance(project)
.shortenClassReferences(tmsLink);
}
}
Формируем текст аннотации
128. Добавили импорт аннотации
public class AddFavoritesAfterNoteTest {
@Test
@TmsLink("AE-5")
@DisplayName("Добавление в избранное после создания заметки")
public void shouldAddToFavoriteAfterNodeTest() { ... }
@Test
@DisplayName("Удаление из избранного после удаления заметки")
public void shouldDeleteToFavoriteAfterNodeTest() { ... }
}
134. Создаем JiraLabelsImportAction
public class JiraLabelsImportAction extends AnAction {
@Override
public void actionPerformed(AnActionEvent event) {
PsiElement element = event.getData(PSI_ELEMENT)
if (element instance of PsiClass) {
addTagsToClassMethods((PsiClass)element)
}
}
}
135. public class JiraLabelsImportAction extends AnAction {
void addTagsToClassMethods(PsiClass testClass) {
Arrays.stream(testClass.getMethods())
.filter(m -> m.hasAnnotation("org..TmsLink"))
.forEach(this::addTmsLinkToMethod)
}
}
Фильтруем методы с ключом
137. Получили ключи тестов
public class AddFavoritesAfterNoteTest {
@Test
@TmsLink("AE-5")
@DisplayName("Добавление в избранное после создания заметки")
public void shouldAddToFavoriteAfterNodeTest() { ... }
@Test
@TmsLink("AE-4")
@DisplayName("Удаление из избранного после удаления заметки")
public void shouldDeleteToFavoriteAfterNodeTest() { ... }
}
144. Добавили теги в тест
public class AddFavoritesAfterNoteTest {
@Test
@TmsLink("AE-5")
@org..Tags({@org..Tag("regress")})
@DisplayName("Добавление в избранное после создания заметки")
public void shouldAddToFavoriteAfterNodeTest() { ... }
}
145. public class JiraLabelsImportAction extends AnAction {
void addTagsToMethod(PsiMethod testMethod) {
addImport(testMethod.getContainingFile(), "org..Tag");
addImport(testMethod.getContainingFile(), "org..Tags");
// код из предыдущего слайда с write операцией
optimizeImports(testMethod.getContainingFile());
}
}
Оптимизируем импорты
146. Добавили теги в тест
public class AddFavoritesAfterNoteTest {
@Test
@TmsLink("AE-5")
@Tags({@Tag("regress")})
@DisplayName("Добавление в избранное после создания заметки")
public void shouldAddToFavoriteAfterNodeTest() { ... }
}
Оптимизировали импорты
147.
148.
149. Какие еще есть идеи?
Импорт сценария теста
Импорт Feature/Story
Включение/выключение
157. public class AddFavoritesAfterNoteTest {
@Test
@TmsLink("AE-5")
@Features({@Feature("Favorites")})
@Stories({@Story("Add favorites after note")})
@DisplayName("Добавление в избранное после создания заметки")
public void shouldAddToFavoriteAfterNodeTest() {
steps.openMainPage();
...
}
}
Мета информация
158. public class AddFavoritesAfterNoteTest {
@Test
@TmsLink("AE-5")
@Features({@Feature("Favorites")})
@Stories({@Story("Add favorites after note")})
@DisplayName("Добавление в избранное после создания заметки")
public void shouldAddToFavoriteAfterNodeTest() {
steps.openMainPage();
...
}
}
Сценарий теста
164. Создаем TestCaseExportAction
public class TestCaseExportAction extends AnAction {
@Override
public void actionPerformed(AnActionEvent event) {
PsiElement element = event.getData(PSI_ELEMENT);
List<TestCase> testcases =
Arrays.stream(((PsiClass) element).getMethods())
.filter(m -> m.hasAnnotation("org..Test"))
.map(this::getTestCaseFromMethod)
.collect(Collectors.toList());
writeTestCases(event.getProject(), testcases);
}
}
165. Берем все методы тестов
public class TestCaseExportAction extends AnAction {
@Override
public void actionPerformed(AnActionEvent event) {
PsiElement element = event.getData(PSI_ELEMENT);
List<TestCase> testcases =
Arrays.stream(((PsiClass) element).getMethods())
.filter(m -> m.hasAnnotation("org..Test"))
.map(this::getTestCaseFromMethod)
.collect(Collectors.toList());
writeTestCases(event.getProject(), testcases);
}
}
166. Собираем информацию
public class TestCaseExportAction extends AnAction {
@Override
public void actionPerformed(AnActionEvent event) {
PsiElement element = event.getData(PSI_ELEMENT);
List<TestCase> testcases =
Arrays.stream(((PsiClass) element).getMethods())
.filter(m -> m.hasAnnotation("org..Test"))
.map(this::getTestCaseFromMethod)
.collect(Collectors.toList());
writeTestCases(event.getProject(), testcases);
}
}
167. Сохраняем результат
public class TestCaseExportAction extends AnAction {
@Override
public void actionPerformed(AnActionEvent event) {
PsiElement element = event.getData(PSI_ELEMENT);
List<TestCase> testcases =
Arrays.stream(((PsiClass) element).getMethods())
.filter(m -> m.hasAnnotation("org..Test"))
.map(this::getTestCaseFromMethod)
.collect(Collectors.toList());
writeTestCases(event.getProject(), testcases);
}
}
168. Как собираем данные метода?
public class TestCaseExportAction extends AnAction {
public TestCase getTestCaseFromMethod(PsiMethod method) {
TestCase testCase = new TestCase();
testCase.setId(getTmsLinkText(method));
testCase.setName(getDisplayNameText(method));
testCase.setFeature(getFeaturesText(method));
testCase.setStories(getStoriesText(method));
testCase.setSteps(getSteps(method));
return testCase;
}
}
169. Уже делали раньше
public class TestCaseExportAction extends AnAction {
public TestCase getTestCaseFromMethod(PsiMethod method) {
TestCase testCase = new TestCase();
testCase.setId(getTmsLinkText(method));
testCase.setName(getDisplayNameText(method));
testCase.setFeature(getFeaturesText(method));
testCase.setStories(getStoriesText(method));
testCase.setSteps(getSteps(method));
return testCase;
}
}
170. public class AddFavoritesAfterNoteTest {
@Test
@TmsLink("AE-5")
@Features({@Feature("Favorites")})
@Stories({@Story("Add favorites after note")})
@DisplayName("Добавление в избранное после создания заметки")
public void shouldAddToFavoriteAfterNodeTest() {
steps.openMainPage();
...
}
}
Уже делали раньше
171. Тоже самое, только массивы
public class TestCaseExportAction extends AnAction {
public TestCase getTestCaseFromMethod(PsiMethod method) {
TestCase testCase = new TestCase();
testCase.setId(getTmsLinkText(method));
testCase.setName(getDisplayNameText(method));
testCase.setFeature(getFeaturesText(method));
testCase.setStories(getStoriesText(method));
testCase.setSteps(getSteps(method));
return testCase;
}
}
172. public class AddFavoritesAfterNoteTest {
@Test
@TmsLink("AE-5")
@Features({@Feature("Favorites")})
@Stories({@Story("Add favorites after note")})
@DisplayName("Добавление в избранное после создания заметки")
public void shouldAddToFavoriteAfterNodeTest() {
steps.openMainPage();
...
}
}
Тоже самое, только массивы
173. А вот это не тривиально
public class TestCaseExportAction extends AnAction {
public TestCase getTestCaseFromMethod(PsiMethod method) {
TestCase testCase = new TestCase();
testCase.setId(getTmsLinkText(method));
testCase.setName(getDisplayNameText(method));
testCase.setFeature(getFeaturesText(method));
testCase.setStories(getStoriesText(method));
testCase.setSteps(getSteps(method));
return testCase;
}
}
174. public class AddFavoritesAfterNoteTest {
@Test
public void shouldAddToFavoriteAfterNodeTest() {
steps.openMainPage();
steps.openAutoCardPage("Volvo XC90")
steps.addNotesToAutoCard("в хорошем состоянии");
steps.openFavoritesPage("в хорошем состоянии");
steps.checkFavoritesListContains("Volvo XC90")
}
}
Сценарий теста
175. Добываем список Шагов
public class ScenarioExportAction extends AnAction {
public List<String> getSteps(PsiMethod testMethod) {
Arrays.stream(method.getBody().getStatements())
.filter(PsiMethodCallExpression.class::isInstance)
.map(PsiMethodClassExpression.class::cast)
.map(PsiMethodClassExpression::resolveMethod())
.filter(m -> m.hasAnnotation("...Step"))
.map(m -> m.getAnnotation("...Step"))
.map(a -> a.findDeclaredAttribute("value"))
.map(PsiAnnotationMemberValue::getText)
.forEach(Collectors.toList())
}
}
176. public class AddFavoritesAfterNoteTest {
@Test
public void shouldAddToFavoriteAfterNodeTest() {
steps.openMainPage();
steps.openAutoCardPage("Volvo XC90")
steps.addNotesToAutoCard("в хорошем состоянии");
steps.openFavoritesPage();
steps.checkFavoritesListContains("Volvo XC90")
}
}
Не метод, а оператор вызова
PsiMethodCallExpression
177. Добываем список методов
public class ScenarioExportAction extends AnAction {
public List<String> getSteps(PsiMethod testMethod) {
Arrays.stream(method.getBody().getStatements())
.filter(PsiMethodCallExpression.class::isInstance)
.map(PsiMethodClassExpression.class::cast)
.map(PsiMethodClassExpression::resolveMethod)
.filter(m -> m.hasAnnotation("...Step"))
.map(m -> m.getAnnotation("...Step"))
.map(a -> a.findDeclaredAttribute("value"))
.map(PsiAnnotationMemberValue::getText)
.forEach(Collectors.toList())
}
}
178. public class BasicSteps {
@Step("Открываем главную страницу")
public void openMainPage() { ... }
@Step("Открываем страницу машины марки {mark}")
public void openAutoCardPage(String mark) { ... }
@Step("Добавляем заметку {text} к машине")
public void addNotesToAutoCard(String text) { ... }
private void utilityMethod { ... }
}
Получили реальные методы
конкретный PsiMethod
179. Добываем список шагов
public class ScenarioExportAction extends AnAction {
public List<String> getSteps(PsiMethod testMethod) {
Arrays.stream(method.getBody().getStatements())
.filter(PsiMethodCallExpression.class::isInstance)
.map(PsiMethodClassExpression.class::cast)
.map(PsiMethodClassExpression::resolveMethod())
.filter(m -> m.hasAnnotation("...Step"))
.map(m -> m.getAnnotation("...Step"))
.map(a -> a.findDeclaredAttribute("value"))
.map(PsiAnnotationMemberValue::getText)
.forEach(Collectors.toList())
}
}
180. Получили текст аннотации
public class BasicSteps {
@Step("Открываем главную страницу")
public void openMainPage() { ... }
@Step("Открываем страницу машины марки {mark}")
public void openAutoCardPage(String mark) { ... }
@Step("Добавляем заметку {text} к машине")
public void addNotesToAutoCard(String text) { ... }
private void utilityMethod { ... }
}
181. Добываем список Шагов
public class ScenarioExportAction extends AnAction {
public List<String> getSteps(PsiMethod testMethod) {
Arrays.stream(method.getBody().getStatements())
.filter(PsiMethodCallExpression.class::isInstance)
.map(PsiMethodClassExpression.class::cast)
.map(PsiMethodClassExpression::resolveMethod())
.filter(m -> m.hasAnnotation("...Step"))
.map(m -> m.getAnnotation("...Step"))
.map(a -> a.findDeclaredAttribute("value"))
.map(PsiAnnotationMemberValue::getText)
.forEach(Collectors.toList())
}
}
182. Как сохранить результат?
public class TestCaseExportAction extends AnAction {
public void writeTestCases(Project project,
List<TestCase> testCases) {
String content = FreemarketUtls
.processTemplate("testcases.ftl", testCases);
Path projectDir = Paths.get(project.getBasePath())
Path indexFile = projectDir.resolve("index.html");
Files.write(indexFile, content.getBytes());
}
}