Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
[RU] Codegeneration as way to help test automat...
Search
Merkushev Kirill
March 15, 2017
Programming
0
83
[RU] Codegeneration as way to help test automation engeneers
Slides from Wrike's automation meetup
Merkushev Kirill
March 15, 2017
Tweet
Share
More Decks by Merkushev Kirill
See All by Merkushev Kirill
Проект на Java и библиотеке Reactor - а как же тесты?
lanwen
0
99
Your tests will ask you to repeat. Scallable Immutable Selenium Infrastructure.
lanwen
1
350
[RU] Codegeneration in Java as way to solve autotest problems
lanwen
0
180
Juseppe
lanwen
1
580
[RU] GIMME your first Autotest!
lanwen
1
410
SPb Jenkins Meetup #0 Как начать писать плагин для Jenkins? И когда этого не делать?
lanwen
3
690
Other Decks in Programming
See All in Programming
CursorはMCPを使った方が良いぞ
taigakono
1
220
Hypervel - A Coroutine Framework for Laravel Artisans
albertcht
1
110
PHPで始める振る舞い駆動開発(Behaviour-Driven Development)
ohmori_yusuke
2
250
datadog dash 2025 LLM observability for reliability and stability
ivry_presentationmaterials
0
440
LT 2025-06-30: プロダクトエンジニアの役割
yamamotok
0
680
ISUCON研修おかわり会 講義スライド
arfes0e2b3c
0
300
20250704_教育事業におけるアジャイルなデータ基盤構築
hanon52_
5
470
Modern Angular with Signals and Signal Store:New Rules for Your Architecture @enterJS Advanced Angular Day 2025
manfredsteyer
PRO
0
180
Team operations that are not burdened by SRE
kazatohiei
1
290
Blazing Fast UI Development with Compose Hot Reload (droidcon New York 2025)
zsmb
1
280
PostgreSQLのRow Level SecurityをPHPのORMで扱う Eloquent vs Doctrine #phpcon #track2
77web
2
490
システム成長を止めない!本番無停止テーブル移行の全貌
sakawe_ee
1
160
Featured
See All Featured
Put a Button on it: Removing Barriers to Going Fast.
kastner
60
3.9k
Easily Structure & Communicate Ideas using Wireframe
afnizarnur
194
16k
GraphQLとの向き合い方2022年版
quramy
49
14k
What's in a price? How to price your products and services
michaelherold
246
12k
Let's Do A Bunch of Simple Stuff to Make Websites Faster
chriscoyier
507
140k
Product Roadmaps are Hard
iamctodd
PRO
54
11k
Producing Creativity
orderedlist
PRO
346
40k
The Success of Rails: Ensuring Growth for the Next 100 Years
eileencodes
45
7.5k
Music & Morning Musume
bryan
46
6.6k
Designing Dashboards & Data Visualisations in Web Apps
destraynor
231
53k
Building Flexible Design Systems
yeseniaperezcruz
328
39k
Code Reviewing Like a Champion
maltzj
524
40k
Transcript
Кодогенерация Меркушев Кирилл как способ решения проблем автоматизатора руководитель группы
автоматизации процессов разработки и тестирования в Яндексе
2 Что искать Куда копать Как копать
3 Что искать Куда копать Как копать
4 Задача: Написать ряд классов для передачи данных public class
UserMeta { private String lang; private String login; }
5 <plugin> <groupId>org.jvnet.jaxb2.maven2</groupId> <artifactId>maven-jaxb2-plugin</artifact> </plugin> JAXB
6 <xs:complexType name="UserMeta"> <xs:sequence> <xs:element name="lang" type="xs:string"/> <xs:element name="login" type="xs:string"/>
</xs:sequence> </xs:complexType> public class UserMeta implements Serializable { private String lang; private String login; // 150+ строк }
7 <plugin> <groupId>org.jvnet.jaxb2.maven2</groupId> <artifactId>maven-jaxb2-plugin</artifact> <configuration> <args> <arg>-Xxew</arg> <arg>-Xfluent-api</arg> </args> </configuration>
//. . . JAXB Магия расширений
8 with-методы (fluent-builder) new UserMeta() .withLogin("Gandalf") .withLang("Syndarin") Immutable Builders toString/hashCode/equals
. . . x100500
9 Задача: Поменять тип поля во множестве классов public class
Meta { private long plannedDateTime; } public class Meta { private ZonedDateTime plannedDateTime; }
10 «Биндинги» <jaxb:globalBindings> <xjc:serializable uid="271283517"/> <jaxb:javaType name="java.time.ZonedDateTime" xmlType="xs:dateTime" parseMethod="Adapter.parse" printMethod="Adapter.print"/>
</jaxb:globalBindings> @XmlJavaTypeAdapter(Adapter1 .class) @XmlSchemaType(name = "dateTime") protected ZonedDateTime plannedDateTime; <xs:element name="plannedDateTime" type="xs:dateTime"/> +
11 <plugin> <groupId>org.jsonschema2pojo</groupId> <artifactId>jsonschema2pojo-maven-plugin</artifactId> </plugin> Jsonschema2pojo joelittlejohn/jsonschema2pojo
12 { "bounce": { "final-recipient": "<email>", "status": "<code>", "type": "failed"
} } blog.qatools.ru/maven/json2pojo
13 Задача: Во множестве объектов проверить значения полей
14 По матчеру assertThat( someOwner, both(withEmail(containsString(«@»))).and(withUid(is(uid)) ); в каждую семью
для email для uid java.lang.AssertionError: Expected: email a string containing "mylogin" but: email was null
15 <dependency> <groupId>ru.yandex.qatools.processors</groupId> <artifactId>feature-matcher-generator</artifactId> <scope>provided</scope> </dependency> yandex-qatools/hamcrest-pojo-matcher-generator
16 Задача: Выполнять HTTP запросы для тестов
17 HttpClient client = new DefaultHttpClient(); HttpPost post = new
HttpPost("http://restUrl"); List nameValuePairs = new ArrayList(1); nameValuePairs.add(new BasicNameValuePair("name", «value")); post.setEntity(new UrlEncodedFormEntity(nameValuePairs)); HttpResponse response = client.execute(post); BufferedReader rd = new BufferedReader( new InputStreamReader(response.getEntity().getContent()) ); // . . .
18 rest-assured.io when().get("/info/{uid}", 5) .then().statusCode(200);
19 String value = when().get("/info/{uid}", 5) .setBasePath(«…») .spec(specification) .body(object) .param(«q»,
«1») .param(«q2», «2») .param(«q3», «3») .then().statusCode(200).extract().asString();
20 Rest-Assured RAML Codegen <plugin> <groupId>ru.lanwen.raml</groupId> <artifactId>rarc-maven-plugin</artifactId> <executions> <execution> <goals>
<goal>generate-client</goal> </goals> <configuration> <basePackage>ru.lanwen.raml.test</basePackage> </configuration> </execution> </executions> </plugin> qameta/rarc
21 #%RAML 0.8 title: Example baseUri: https://api.example.com /info: is: [authorized-by-token]
get: displayName: fetch description: Fetch list queryParameters: uid: ApiExample.example(exampleConfig()) .rpcApi() .info().withUid("1") .fetch(identity()).prettyPeek();
22 Что искать Куда копать Как копать
23 353 3048 4060 бины матчеры 1800 102 клиент LoC
xml raml Необольшой проект
24 Java - Go - Python - Java xml, json
- протокол
25 автоматизация - не только в тестах
26 Что искать Куда копать Как копать
27 Пишет код Стартует процесс
28 Пишет код Императивно Декларативно
29 Пишет код Императивно Декларативно square/javapoet jknack/handlebars.java
30 package com.example.helloworld; public final class HelloWorld { public static
void main(String[] args) { System.out.println("Hello, World!"); } }
31 MethodSpec main = MethodSpec.methodBuilder("main") .addModifiers(Modifier.PUBLIC, Modifier.STATIC) .returns(void.class) .addParameter(String[].class, "args")
.addStatement("$T.out.println($S)", System.class, "Hello, JavaPoet!") .build(); TypeSpec helloWorld = TypeSpec.classBuilder("HelloWorld") .addModifiers(Modifier.PUBLIC, Modifier.FINAL) .addMethod(main) .build(); square/javapoet
32 jknack/handlebars.java package {{package_name}}; public final class {{class_name}} { {{#methods}}
public static void {{name}}({{arg_type}} arg) { System.out.println("Hello, World!"); } {{/methods}} }
33 Императивно Декларативно Сложные отношения в коде Когда: Важна читаемость
результата Много логики в процессе генерации
34 Императивно Декларативно Сложные отношения в коде Когда: Важна читаемость
результата Много логики в процессе генерации Когда: Исходник - плоская модель Нужно быстро
35 Стартует процесс Annotation Processors Расширения билд-системы maven, gradle core
java
36 @SupportedSourceVersion(SourceVersion.RELEASE_8) @SupportedAnnotationTypes({«fqpn.AnnoClassName»}) public class MatcherFactoryGenerator extends AbstractProcessor { }
resources/META-INF/services/javax.annotation.processing.Processor 1 Процессор аннотаций FQCN
37 2 Процессор аннотаций @Override public boolean process(Set<? extends TypeElement>
annotations, RoundEnvironment roundEnv) { for (TypeElement annotation : annotations) { roundEnv.getElementsAnnotatedWith(annotation) .stream() .filter(isEntryWithParentPackageElement()) .map(Proc::asCode) .map(ClassSpecDescription::asJavaFile) .forEach(write(processingEnv)); } return false; } Обработка
38 Тестируемся E2E unit-тесты Отдельный модуль google/compile-testing
39 Тестируемся unit-тесты google/compile-testing Compilation compilation = javac() .withProcessors(new MyAnnotationProcessor())
.compile(JavaFileObjects.forResource(«HelloWorld.java»)); assertThat(compilation).succeeded(); assertThat(compilation) .generatedSourceFile("GeneratedHelloWorld") .hasSourceEquivalentTo(JavaFileObjects.forResource("GeneratedHelloWorld.java"));
40 1 Maven plugin @Mojo(name = "generate-client", defaultPhase = LifecyclePhase.GENERATE_SOURCES)
@Execute(goal = "generate-client") public class RestAssuredClientGenerateMojo extends AbstractMojo { } bit.ly/mvn-plugin-dev
41 2 Maven plugin @Parameter(required = true, readonly = true,
defaultValue = "${project}") private MavenProject project; @Override public void execute() throws MojoExecutionException, MojoFailureException { new Codegen().generate(); project.addCompileSourceRoot(outputDir); } bit.ly/mvn-plugin-dev Магия генерации
42 Что искать Куда копать Как копать
43 Спасибо Меркушев Кирилл lanwen руководитель группы автоматизации процессов разработки
и тестирования в Яндексе