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
93
[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
100
Your tests will ask you to repeat. Scallable Immutable Selenium Infrastructure.
lanwen
1
370
[RU] Codegeneration in Java as way to solve autotest problems
lanwen
0
180
Juseppe
lanwen
1
620
[RU] GIMME your first Autotest!
lanwen
1
430
SPb Jenkins Meetup #0 Как начать писать плагин для Jenkins? И когда этого не делать?
lanwen
3
750
Other Decks in Programming
See All in Programming
[KNOTS 2026登壇資料]AIで拡張‧交差する プロダクト開発のプロセス および携わるメンバーの役割
hisatake
0
290
Claude Codeと2つの巻き戻し戦略 / Two Rewind Strategies with Claude Code
fruitriin
0
140
CSC307 Lecture 08
javiergs
PRO
0
670
プロダクトオーナーから見たSOC2 _SOC2ゆるミートアップ#2
kekekenta
0
220
dchart: charts from deck markup
ajstarks
3
1k
Automatic Grammar Agreementと Markdown Extended Attributes について
kishikawakatsumi
0
200
AI Schema Enrichment for your Oracle AI Database
thatjeffsmith
0
310
izumin5210のプロポーザルのネタ探し #tskaigi_msup
izumin5210
1
140
Rust 製のコードエディタ “Zed” を使ってみた
nearme_tech
PRO
0
200
CSC307 Lecture 02
javiergs
PRO
1
780
AI によるインシデント初動調査の自動化を行う AI インシデントコマンダーを作った話
azukiazusa1
1
740
React 19でつくる「気持ちいいUI」- 楽観的UIのすすめ
himorishige
11
7.5k
Featured
See All Featured
Navigating the moral maze — ethical principles for Al-driven product design
skipperchong
2
250
How To Stay Up To Date on Web Technology
chriscoyier
791
250k
Building the Perfect Custom Keyboard
takai
2
690
The AI Revolution Will Not Be Monopolized: How open-source beats economies of scale, even for LLMs
inesmontani
PRO
3
3k
30 Presentation Tips
portentint
PRO
1
220
My Coaching Mixtape
mlcsv
0
48
Stop Working from a Prison Cell
hatefulcrawdad
273
21k
How to Build an AI Search Optimization Roadmap - Criteria and Steps to Take #SEOIRL
aleyda
1
1.9k
End of SEO as We Know It (SMX Advanced Version)
ipullrank
3
3.9k
The agentic SEO stack - context over prompts
schlessera
0
640
XXLCSS - How to scale CSS and keep your sanity
sugarenia
249
1.3M
The Myth of the Modular Monolith - Day 2 Keynote - Rails World 2024
eileencodes
26
3.3k
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 руководитель группы автоматизации процессов разработки
и тестирования в Яндексе