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
95
[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
380
[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
760
Other Decks in Programming
See All in Programming
CSC307 Lecture 14
javiergs
PRO
0
470
New in Go 1.26 Implementing go fix in product development
sunecosuri
0
430
AIとペアプロして処理時間を97%削減した話 #pyconshizu
kashewnuts
1
230
Codexに役割を持たせる 他のAIエージェントと組み合わせる実務Tips
o8n
4
1.3k
PostgreSQL を使った快適な go test 環境を求めて
otakakot
0
540
new(1.26) ← これすき / kamakura.go #8
utgwkk
0
2.3k
Ruby and LLM Ecosystem 2nd
koic
1
680
「やめとこ」がなくなった — 1月にZennを始めて22本書いた AI共創開発のリアル
atani14
0
380
AWS Infrastructure as Code の新機能 2025 総まとめ 〜SA 4人による怒涛のデモ祭り〜
konokenj
10
3.3k
クライアントワークでSREをするということ。あるいは事業会社におけるSREと同じこと・違うこと
nnaka2992
1
340
Vuetify 3 → 4 何が変わった?差分と移行ポイント10分まとめ
koukimiura
0
130
The Past, Present, and Future of Enterprise Java
ivargrimstad
0
310
Featured
See All Featured
Digital Projects Gone Horribly Wrong (And the UX Pros Who Still Save the Day) - Dean Schuster
uxyall
0
700
AI Search: Implications for SEO and How to Move Forward - #ShenzhenSEOConference
aleyda
1
1.2k
The Director’s Chair: Orchestrating AI for Truly Effective Learning
tmiket
1
130
The untapped power of vector embeddings
frankvandijk
2
1.6k
Unsuck your backbone
ammeep
672
58k
Discover your Explorer Soul
emna__ayadi
2
1.1k
Are puppies a ranking factor?
jonoalderson
1
3.1k
Leveraging Curiosity to Care for An Aging Population
cassininazir
1
190
I Don’t Have Time: Getting Over the Fear to Launch Your Podcast
jcasabona
34
2.7k
How to Build an AI Search Optimization Roadmap - Criteria and Steps to Take #SEOIRL
aleyda
1
2k
世界の人気アプリ100個を分析して見えたペイウォール設計の心得
akihiro_kokubo
PRO
67
37k
We Analyzed 250 Million AI Search Results: Here's What I Found
joshbly
1
960
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 руководитель группы автоматизации процессов разработки
и тестирования в Яндексе