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
120
0
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
[RU] Codegeneration as way to help test automation engeneers
Slides from Wrike's automation meetup
Merkushev Kirill
March 15, 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 in Java as way to solve autotest problems
lanwen
0
200
Juseppe
lanwen
1
660
[RU] GIMME your first Autotest!
lanwen
1
440
SPb Jenkins Meetup #0 Как начать писать плагин для Jenkins? И когда этого не делать?
lanwen
3
780
Other Decks in Programming
See All in Programming
Foundry Localでエージェント開発
seosoft
0
140
{ Android | Kotlin } Gradle Plugin in 2026
ryunen344
1
290
Pythonの実行はどこまで賢くなったのか? CPythonとPyPyから見る最適化のしくみ
curekoshimizu
4
2.8k
Claude Codeを組織的に動かして月400PRを実現した話
happy_ryo
0
260
tsc.rip を支える技術 / Kyoto.なんか #8
susisu
0
4.3k
AIは賢い。でも実行環境は? CLIおじさんがAI時代に伝えたいこと ~ CLIおじさんがAI時代に伝えたいこと ~
curekoshimizu
1
160
レビュー履歴をAIに食わせて、 Compose移行を加速するs
shihochan
0
270
新人はどこまで自力でやり、どこからAIに頼るべきか/エンジニア育成に向き合う_先輩たちの悩みと知見共有会
toppan_digital_dev
1
560
20260828_品質と開発生産性を両立させる、AI時代のE2Eテストの考え方
magicpod
0
160
アクセシビリティから考える情報設計
high_g_engineer
0
240
Vibes Containers 〜AIで変わるコンテナ設計と運用〜
tkikuc
1
500
業務時間外もAIに働いてもらう話
colorful12
3
10k
Featured
See All Featured
Context Engineering - Making Every Token Count
addyosmani
9
1.1k
Between Models and Reality
mayunak
4
450
B2B Lead Gen: Tactics, Traps & Triumph
marketingsoph
0
230
A Modern Web Designer's Workflow
chriscoyier
698
190k
A Soul's Torment
seathinner
7
3.6k
How STYLIGHT went responsive
nonsquared
100
6.3k
16th Malabo Montpellier Forum Presentation
akademiya2063
PRO
0
370
Design of three-dimensional binary manipulators for pick-and-place task avoiding obstacles (IECON2024)
konakalab
0
580
Pawsitive SEO: Lessons from My Dog (and Many Mistakes) on Thriving as a Consultant in the Age of AI
davidcarrasco
0
240
Sam Torres - BigQuery for SEOs
techseoconnect
PRO
0
530
Taking LLMs out of the black box: A practical guide to human-in-the-loop distillation
inesmontani
PRO
3
2.4k
The Director’s Chair: Orchestrating AI for Truly Effective Learning
tmiket
1
290
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 руководитель группы автоматизации процессов разработки
и тестирования в Яндексе