Slide 1

Slide 1 text

Кодогенерация Меркушев Кирилл как способ решения проблем автоматизатора руководитель группы автоматизации процессов разработки и тестирования в Яндексе

Slide 2

Slide 2 text

2 Что искать Куда копать Как копать

Slide 3

Slide 3 text

3 Что искать Куда копать Как копать

Slide 4

Slide 4 text

4 Задача: Написать ряд классов для передачи данных public class UserMeta { private String lang; private String login; }


Slide 5

Slide 5 text

5 
 org.jvnet.jaxb2.maven2
 maven-jaxb2-plugin JAXB

Slide 6

Slide 6 text

6 
 
 
 
 
 public class UserMeta implements Serializable { private String lang; private String login; // 150+ строк
 }


Slide 7

Slide 7 text

7 
 org.jvnet.jaxb2.maven2
 maven-jaxb2-plugin 
 
 -Xxew
 -Xfluent-api
 
 //. . . JAXB Магия расширений

Slide 8

Slide 8 text

8 with-методы (fluent-builder) new UserMeta() .withLogin("Gandalf") .withLang("Syndarin") Immutable Builders toString/hashCode/equals . . . x100500

Slide 9

Slide 9 text

9 Задача: Поменять тип поля во множестве классов public class Meta { private long plannedDateTime; }
 public class Meta { private ZonedDateTime plannedDateTime; }


Slide 10

Slide 10 text

10 «Биндинги» 
 
 
 @XmlJavaTypeAdapter(Adapter1 .class) @XmlSchemaType(name = "dateTime") protected ZonedDateTime plannedDateTime; +

Slide 11

Slide 11 text

11 
 org.jsonschema2pojo
 jsonschema2pojo-maven-plugin
 Jsonschema2pojo joelittlejohn/jsonschema2pojo

Slide 12

Slide 12 text

12 { "bounce": { "final-recipient": "", "status": "", "type": "failed" } } blog.qatools.ru/maven/json2pojo

Slide 13

Slide 13 text

13 Задача: Во множестве объектов проверить значения полей

Slide 14

Slide 14 text

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

Slide 15

Slide 15 text

15 ru.yandex.qatools.processors feature-matcher-generator provided yandex-qatools/hamcrest-pojo-matcher-generator

Slide 16

Slide 16 text

16 Задача: Выполнять HTTP запросы для тестов

Slide 17

Slide 17 text

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()) ); // . . .

Slide 18

Slide 18 text

18 rest-assured.io when().get("/info/{uid}", 5) .then().statusCode(200);

Slide 19

Slide 19 text

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();

Slide 20

Slide 20 text

20 Rest-Assured RAML Codegen 
 ru.lanwen.raml
 rarc-maven-plugin
 
 
 
 generate-client
 
 
 ru.lanwen.raml.test
 
 
 
 qameta/rarc

Slide 21

Slide 21 text

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();

Slide 22

Slide 22 text

22 Что искать Куда копать Как копать

Slide 23

Slide 23 text

23 353 3048 4060 бины матчеры 1800 102 клиент LoC xml raml Необольшой проект

Slide 24

Slide 24 text

24 Java - Go - Python - Java xml, json - протокол

Slide 25

Slide 25 text

25 автоматизация - не только в тестах

Slide 26

Slide 26 text

26 Что искать Куда копать Как копать

Slide 27

Slide 27 text

27 Пишет код Стартует процесс

Slide 28

Slide 28 text

28 Пишет код Императивно Декларативно

Slide 29

Slide 29 text

29 Пишет код Императивно Декларативно square/javapoet jknack/handlebars.java

Slide 30

Slide 30 text

30 package com.example.helloworld; public final class HelloWorld { public static void main(String[] args) { System.out.println("Hello, World!"); } }

Slide 31

Slide 31 text

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

Slide 32

Slide 32 text

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}} }

Slide 33

Slide 33 text

33 Императивно Декларативно Сложные отношения в коде Когда: Важна читаемость результата Много логики в процессе генерации

Slide 34

Slide 34 text

34 Императивно Декларативно Сложные отношения в коде Когда: Важна читаемость результата Много логики в процессе генерации Когда: Исходник - плоская модель Нужно быстро

Slide 35

Slide 35 text

35 Стартует процесс Annotation Processors Расширения билд-системы maven, gradle core java

Slide 36

Slide 36 text

36 @SupportedSourceVersion(SourceVersion.RELEASE_8) @SupportedAnnotationTypes({«fqpn.AnnoClassName»}) public class MatcherFactoryGenerator extends AbstractProcessor { } resources/META-INF/services/javax.annotation.processing.Processor 1 Процессор аннотаций FQCN

Slide 37

Slide 37 text

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; } Обработка

Slide 38

Slide 38 text

38 Тестируемся E2E unit-тесты Отдельный модуль google/compile-testing

Slide 39

Slide 39 text

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"));

Slide 40

Slide 40 text

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

Slide 41

Slide 41 text

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 Магия генерации

Slide 42

Slide 42 text

42 Что искать Куда копать Как копать

Slide 43

Slide 43 text

43 Спасибо Меркушев Кирилл lanwen руководитель группы автоматизации процессов разработки и тестирования в Яндексе