Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Sign up for free
Menu
Search
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Pricing
Search
Sign in
Sign up for free
[RU] Codegeneration in Java as way to solve aut...
Search
Merkushev Kirill
June 04, 2017
Programming
210
0
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
[RU] Codegeneration in Java as way to solve autotest problems
It was presented on Heisenbug 2017 (June) in Saint-Petersburg
Merkushev Kirill
June 04, 2017
More Decks by Merkushev Kirill
See All by Merkushev Kirill
Проект на Java и библиотеке Reactor - а как же тесты?
lanwen
0
120
Your tests will ask you to repeat. Scallable Immutable Selenium Infrastructure.
lanwen
1
420
[RU] Codegeneration as way to help test automation engeneers
lanwen
0
120
Juseppe
lanwen
1
670
[RU] GIMME your first Autotest!
lanwen
1
450
SPb Jenkins Meetup #0 Как начать писать плагин для Jenkins? И когда этого не делать?
lanwen
3
790
Other Decks in Programming
See All in Programming
そのリトライ、死んだコネクションを使い回していませんか ── GoのHTTPクライアントとHTTP/2を実プロダクト障害から学び直す
myus4a
0
390
ハーネス設計入門 〜 基礎知識の整理から実務へのステップアップ 〜
kinopeee
21
21k
Ghostty + Neovimで作る 透明でカッコ良い開発環境
j341nono
0
150
KiroのSpecで「五目並べ」を作ってみる
satoshi256kbyte
1
360
IBM Bob Dojo #1 仕様駆動開発入門
oniak3ibm
PRO
0
350
RAG の “R” を Swift で覗いてみる 〜「意味から探す」検索の仕組み〜
nao_randd
0
120
Streamlitで実現する自然言語データアプリ開発
ayumu_yamaguchi
1
340
月間100万人のサービス刷新で、 技術選定をHonoに振り切った話
yutobara
2
1.2k
Findy - エンジニア向け会社紹介/Findy Company Deck
findyinc
6
400k
Are APIs Still Relevant in the AI Era?
soyuka
0
430
Agentic Software Factoryに、すごく賢いIF文を。 / super smart IF statement into the Agentic Software Factory.
rkaga
8
1.9k
Domain-Driven Transformation
hschwentner
2
2.3k
Featured
See All Featured
The Organizational Zoo: Understanding Human Behavior Agility Through Metaphoric Constructive Conversations (based on the works of Arthur Shelley, Ph.D)
kimpetersen
PRO
0
490
Kristin Tynski - Automating Marketing Tasks With AI
techseoconnect
PRO
0
540
A Modern Web Designer's Workflow
chriscoyier
699
190k
jQuery: Nuts, Bolts and Bling
dougneiner
66
8.6k
Product Roadmaps are Hard
iamctodd
55
13k
Into the Great Unknown - MozCon
thekraken
41
2.8k
Statistics for Hackers
jakevdp
799
230k
Navigating Team Friction
lara
192
16k
A Soul's Torment
seathinner
8
3.7k
RailsConf & Balkan Ruby 2019: The Past, Present, and Future of Rails at GitHub
eileencodes
141
35k
Digital Ethics as a Driver of Design Innovation
axbom
PRO
1
450
Introduction to Domain-Driven Design and Collaborative software design
baasie
1
1k
Transcript
Кодогенерация Кирилл Меркушев руководитель группы автоматизации процессов разработки и тестирования
в Яндексе
2 50%
3 Программировать Читать Сопровождать 50%
4 Поменяли шаблон = переписали сотни строк
5 Кодогенерация - это просто и очень полезно
6 5 причин попробовать
7 5 причин попробовать 2 способа сделать больше
8 5 причин попробовать 2 способа сделать больше Откуда дети
исходники
9 5 причин попробовать 2 способа сделать больше Откуда дети
исходники Процессор аннотаций
10 5 причин попробовать 2 способа сделать больше Откуда дети
исходники Процессор аннотаций Мавен плагин
11 * * для привлечения внимания Тестируем приложение «Полетели» lanwen/heisenbug17
- POST /ticket/ - GET /tickets/{uuid}
12 $ cloc Java 366
13 $ cloc 50459 (600 files) Яндекс Паспорт (500+ эндпоинтов,
400 объектов) 20730 (220 files) До После Java
14 Project Lombok projectlombok.org 1 Зависимость @Data аннотация
15 Project Lombok 1 … projectlombok.org
16 Project Lombok 1 Зависимость @Data аннотация IDE plugin projectlombok.org
17 Jsonschema2pojo 2 Plugin сборки Json joelittlejohn/jsonschema2pojo
18 { "flights": [{ "number": "<num>", "airline": "<code>", "departure": {}
}] } blog.qatools.ru/maven/json2pojo
19 Jsonschema2pojo 2 joelittlejohn/jsonschema2pojo …
20 Json-schema!
21 Json-schema! XSD (XML Schema)
22 JAXB/XJC 3 Plugin сборки XSD (XML Schema)
23 <plugin> <groupId>org.jvnet.jaxb2.maven2</groupId> <artifactId>maven-jaxb2-plugin</artifact> <configuration> <args> <arg>-Xxew</arg> <arg>-Xfluent-api</arg> </args> </configuration>
//. . . JAXB (демо)
24 <plugin> <groupId>org.jvnet.jaxb2.maven2</groupId> <artifactId>maven-jaxb2-plugin</artifact> <configuration> <args> <arg>-Xxew</arg> <arg>-Xfluent-api</arg> </args> </configuration>
//. . . JAXB (демо) Магия расширений
25 with-методы (fluent-builder) new UserMeta() .withLogin("Gandalf") .withLang("Syndarin") Immutable Builders toString/hashCode/equals
. . . x100500
26 Hamcrest Matchers 4 Конфиг Зависимость yandex-qatools/hamcrest-pojo-matcher-generator
27 По матчеру assertThat( someOwner, both(withEmail(containsString(«@»))) .and(withUid(is(uid)) ); в каждую
семью для email для uid java.lang.AssertionError: Expected: email a string containing «@» but: email was null полная свобода
28
29
30 rest-assured.io when().get("/info/{uid}", 5) .then().statusCode(200);
31 RARC 5 Plugin сборки RAML спецификация qameta/rarc
32 #%RAML 0.8 title: Tickets baseUri: https://api.example.com /ticket: /{uuid}: get:
displayName: fetch
33 #%RAML 0.8 title: Tickets baseUri: https://api.example.com /ticket: /{uuid}: get:
displayName: fetch ApiTickets.tickets(ticketsConfig()) .ticket() .uuid().withUuid("1") .fetch(identity()).prettyPeek();
34 #%RAML 0.8 title: Tickets baseUri: https://api.example.com /ticket: /{uuid}: get:
displayName: fetch ApiTickets.tickets(ticketsConfig()) .ticket() .uuid().withUuid("1") .fetch(identity()).prettyPeek();
35 #%RAML 0.8 title: Tickets baseUri: https://api.example.com /ticket: /{uuid}: get:
displayName: fetch ApiTickets.tickets(ticketsConfig()) .ticket() .uuid().withUuid("1") .fetch(identity()).prettyPeek();
36 #%RAML 0.8 title: Tickets baseUri: https://api.example.com /ticket: /{uuid}: get:
displayName: fetch ApiTickets.tickets(ticketsConfig()) .ticket() .uuid().withUuid("1") .fetch(identity()).prettyPeek();
37 $ cloc Java 16 XSD 56 72 366 vs
38 Подводные камни
39 Почему не kotlin/groovy/ scala/go … ?
40 Почему не kotlin/ groovy/scala/go … ? Нельзя!
41 Почему не kotlin/ groovy/scala/go … ? Нельзя! Уже есть
схема
42 Почему не kotlin/ groovy/scala/go … ? Нельзя! Уже есть
схема Кодогенерация - не только про бины
43 Почему не kotlin/ groovy/scala/go … ? Нельзя! Уже есть
схема Кодогенерация - не только про бины lanwen/heisenbug17
44 Тонкая настройка?
45 <xs:element name="plannedDateTime" type="xs:dateTime"/> Схема «Биндинги»
46 «Биндинги» Wat? Схема <xs:element name="plannedDateTime" type="xs:dateTime"/>
47 «Биндинги» @XmlJavaTypeAdapter(Adapter1 .class) @XmlSchemaType(name = "dateTime") protected ZonedDateTime plannedDateTime;
<xs:element name="plannedDateTime" type="xs:dateTime"/> Схема Результат
48 «Биндинги» <jaxb:globalBindings> ... <jaxb:javaType name="java.time.ZonedDateTime" xmlType="xs:dateTime" parseMethod="Adapter.parse" printMethod="Adapter.print"/> </jaxb:globalBindings>
bindings.xjb
49 Программирование на xml/json/yaml?
50 Программирование на xml/json/yaml? Нет логики
51 Программирование на xml/json/yaml? Нет логики Протокол (доки, микросервисы)
52 Программирование на xml/json/yaml? Нет логики Протокол (доки, микросервисы) Как
список покупок
53 Кодогенерация - это просто и очень полезно
54 2 Задачи
55 2 2 + Задачи Решения
56 2 2 + + 2 Задачи Решения Слайда
57 Тестовые методы списком констант public final class TestMethodConsts {
psf String TEST_METHOD_shouldCreate = "ru.lanwen.heisenbug.EticketResourceTest#shouldCreate"; } КОНСТАНТА = "полный.референс#метода"
58 Генерация кода Написание исходников
59 Генерация кода Написание исходников 1
60 Написание исходников StringBuilder 1
61 Написание исходников StringBuilder square/javapoet jknack/handlebars.java 1
62 public final class TestMethodConsts { public static final String
TEST_METHOD_shouldCreate = "ru.lanwen.heisenbug.ETest#shouldCreate"; }
63 square/javapoet FieldSpec.builder( ClassName.get(String.class), key, PUBLIC, STATIC, FINAL ).initializer("$S", value)
.build()
64 square/javapoet FieldSpec.builder( ClassName.get(String.class), key, PUBLIC, STATIC, FINAL ).initializer("$S", value)
.build() Поле
65 square/javapoet FieldSpec.builder( ClassName.get(String.class), key, PUBLIC, STATIC, FINAL ).initializer("$S", value)
.build() Тип, имя и модификаторы
66 square/javapoet FieldSpec.builder( ClassName.get(String.class), key, PUBLIC, STATIC, FINAL ).initializer("$S", value)
.build() Значение
67 jknack/handlebars.java template.apply( Context.newContext() .data("package", pkg) .data("class", className) .data("consts", consts.entrySet()),
writer );
68 Только модель template.apply( Context.newContext() .data("package", pkg) .data("class", className) .data("consts",
consts.entrySet()), writer ); jknack/handlebars.java
69 Генерация кода Написание исходников 1 2
70 Кодогенерация Sed, bash 2
71 Кодогенерация Sed, bash 2 Annotation Processing Maven, Gradle
72 abstract class AbstractProcessor { } Процессор аннотаций
73 MatcherFactoryGenerator extends AbstractProcessor Процессор аннотаций
74 @SupportedSourceVersion(SourceVersion.RELEASE_8) @SupportedAnnotationTypes({"your.awesome.Annotation"}) public class MatcherFactoryGenerator extends AbstractProcessor { }
Процессор аннотаций
75 @SupportedSourceVersion(SourceVersion.RELEASE_8) @SupportedAnnotationTypes({"your.awesome.Annotation"}) public class MatcherFactoryGenerator extends AbstractProcessor { }
resources/META-INF/services/ javax.annotation.processing.Processor Процессор аннотаций FQCN
76 Тесты! E2E unit-тесты Отдельный модуль google/compile-testing
77 Compilation compilation = javac() .withProcessors(new MyAnnotationProcessor()) .compile(JavaFileObjects.forResource("HelloWorld.java")); assertThat(compilation).succeeded(); Тесты!
unit-тесты google/compile-testing
78 public final class Project { public static final String
VERSION = "1.0.0"; } Версия проекта константой
79 Maven plugin public class AbstractMojo { } bit.ly/mvn-plugin-dev
80 Maven plugin RestClientGenerateMojo extends AbstractMojo { } bit.ly/mvn-plugin-dev
81 Maven plugin @Mojo( name = "generate-client", defaultPhase = LifecyclePhase.GENERATE_SOURCES
) @Execute(goal = "generate-client") public class RestClientGenerateMojo extends AbstractMojo { } bit.ly/mvn-plugin-dev
82 @Parameter( required = true, readonly = true, defaultValue =
"${project}" ) private MavenProject project; Знания мавена Maven plugin bit.ly/mvn-plugin-dev
83 . . . private MavenProject project; @Override public void
execute() { new Codegen().generate(); project.addCompileSourceRoot(outputDir); } Магия генерации Maven plugin bit.ly/mvn-plugin-dev
84 Кодогенерируй!
85 Итого
86 Огромное количество готовых инструментов lanwen/heisenbug17 Project Lombok 1 Jsonschema2pojo
2 JAXB/XJC 3 Hamcrest Matchers 4 RARC 5
87 Огромное количество готовых инструментов lanwen/heisenbug17 Есть слабые стороны, при
большой выгоде
88 Огромное количество готовых инструментов lanwen/heisenbug17 Хватит это терпеть писать
toString/equals вручную! Есть слабые стороны, при большой выгоде
89 Спасибо Меркушев Кирилл lanwen руководитель группы автоматизации процессов разработки
и тестирования в Яндексе