Як можна тестувати вебсервіси за допомогою HTTP Client CLI, а також інших інструментів

Усі статті, обговорення, новини про тестування — в одному місці. Підписуйтеся на DOU | QA!

Усім привіт, мене звати Віталій, і у цій статті я розгляну особливості тестування вебсервісів за допомогою HTTP Client CLI, а також коли підтримується взаємодія з WebSockets та gRPC сервісами. Детальніше прочитати про HTTP Client можна (після цієї статті) на сторінці продукту, саме CLI застосунку присвячена окрема сторінка.

Ця стаття в першу чергу націлена на програмістів, а не на тестерів. Хоча тестерам теж може бути цікаво, оскільки IntelliJ HTTP Client є альтернативою Postman, який, як я знаю, широко використовується в роботі наших колег зі сфери QA.

Крім всім відомих юніт-тестів є ще й інтеграційні (принаймі, я намагають використовувати їх у роботі). Для тестування клієнтів вебсервісів є зручна штука MockServer. А от для тестування самих вебсервісів ми зазвичай користувались старим добрим curl. Але всі ці опції... Та і запускати все це не зручно, треба зберігати запити десь у окремому файлі та копіювати.

Коли я розбирався з HTTP Client, знайшов альтернативи, такі як httpie та hurl, останній дуже схожий за ідеологією, раджу подитивитсь на нього також, особливо, якщо ви програмуєте не на Java. Ну, а тепер до справи.

Вступ

В квітні якось трохи випадково натрапив на вебпрезентацію Marco Behler The New HTTP Client CLI, у якій розповідалось про можливості використання HTTP Client у режимі командного рядка. Це відео можна подивитись прямо зараз. На додачу можно подивитись детальніше відео HTTP Client — Secret Weapon for Web Service Testing. Я не буду переповідати те, що розповіли у відео, перейду відразу до практичної частини, яка не потрапила у відео: використання клієнта у проєктах Maven та на платформах GitLab та GitHub.

З використанням наче все просто, якщо у вас встановлена IntelliJ IDEA чи споріднений продукт. АЄОА: якщо треба вбудувати тести у проєкт Maven чи використати їх у GitLab/GitHub/younameit: HTTP Client розповсюджується лише як бінарний застосунок, і підключити його в процес зборки можна лише як зовнішню програму, яку ще й треба попередньо скачати.

Почну з моменту про «скачати»: якщо ви користуєтесь ArchLinux, Manjaro чи іншими похідними, то в AUR доданий пакет intellij-http-client для встановлення ijhhp на комп’ютер, в якому навіть виправлена помилка з версією JDК. Для всіх інших є описані нижче варіанти, які також є у репозиторії на GitHub (кому зручніше на GitLab — там є копія). Ще є варіант з використанням Docker образу jetbrains/intellij-http-client, але я його не розглядав.

Maven

Перший підхід (для мене він був другим) спирається на плагіни download-maven-plugin та exec-maven-plugin. Додаємо у свій проєкт блок, тут я використовую Spring Boot, але, звісно, це може бути будь що.

Перед тестами скачується та розпаковується у target архів з ijhttp та запускається тестований код. Потім через exec запускаються тести, а після їх закінчення Spring Boot зупиняється.

<build>
  <plugins>
    <plugin>
      <artifactId>download-maven-plugin</artifactId>
      <configuration>
        <followRedirects>true</followRedirects>
        <outputDirectory>${project.build.directory}</outputDirectory>
        <unpack>true</unpack>
        <url> https://download-cdn.jetbrains.ком...intellij-http-client.zip
        </url>
      </configuration>
      <executions>
        <execution>
          <goals>
            <goal>wget</goal>
          </goals>
          <id>install-ijhttp</id>
          <phase>pre-integration-test</phase>
        </execution>
      </executions>
      <groupId>com.googlecode.maven-download-plugin</groupId>
      <version>1.7.0</version>
    </plugin>
    <plugin>
      <artifactId>spring-boot-maven-plugin</artifactId>
      <configuration>
        <jmxPort>9002</jmxPort>
      </configuration>
      <executions>
        <execution>
          <goals>
            <goal>start</goal>
          </goals>
          <id>start</id>
          <phase>pre-integration-test</phase>
        </execution>
        <execution>
          <goals>
            <goal>stop</goal>
          </goals>
          <id>stop</id>
          <phase>post-integration-test</phase>
        </execution>
      </executions>
      <groupId>org.springframework.boot</groupId>
      <version>3.0.6</version>
    </plugin>
    <plugin>
      <artifactId>exec-maven-plugin</artifactId>
      <configuration>
        <arguments>
          <argument>--report</argument>
          <argument>your-test-requests.http</argument>
        </arguments>
        <executable>${project.build.directory}/ijhttp/ijhttp</executable>
      </configuration>
      <executions>
        <execution>
          <goals>
            <goal>exec</goal>
          </goals>
          <id>http-test</id>
          <phase>integration-test</phase>
        </execution>
      </executions>
      <groupId>org.codehaus.mojo</groupId>
      <version>3.1.0</version>
    </plugin>
  </plugins>
</build>

Другий підхід, з якого в мене все почалося, — це використання окремого плагіна. Коли дивився перше відео, у коментарях хтось спитав, чи є під це плагін. Я відразу перевірив і виявилось, що немає. Тож вирішив швидко написати.

Але плагін по суті є спрощеним варіантом exec, який вміє запускати лише HTTP Client. Тож не скажу, що він надає якісь великі переваги: трохи простіше і, можливо, зрозуміліше. Плагін не вміє скачувати HTTP Client, тому використання download-maven-plugin все ще потрібне. Може, згодом HTTP Client потрапить у Maven Central, і тоді плагін буде працювати сам собою без жодних додаткових «милиць».

Тут все так само: перед тестами скачуємо ijhttp до target, запускаємо Spring Boot, запускаємо тести і гасимо SpringBoot.

<build>
  <plugins>
    <plugin>
      <artifactId>download-maven-plugin</artifactId>
      <configuration>
        <followRedirects>true</followRedirects>
        <outputDirectory>${project.build.directory}</outputDirectory>
        <unpack>true</unpack>
        <url>
        https://download-cdn.jetbrains.ком...intellij-http-client.zip
        </url>
      </configuration>
      <executions>
        <execution>
          <goals>
            <goal>wget</goal>
          </goals>
          <id>install-ijhttp</id>
          <phase>pre-integration-test</phase>
        </execution>
      </executions>
      <groupId>com.googlecode.maven-download-plugin</groupId>
      <version>1.7.0</version>
    </plugin>
    <plugin>
      <artifactId>spring-boot-maven-plugin</artifactId>
      <configuration>
        <jmxPort>9002</jmxPort>
      </configuration>
      <executions>
        <execution>
          <goals>
            <goal>start</goal>
          </goals>
          <id>start</id>
          <phase>pre-integration-test</phase>
        </execution>
        <execution>
          <goals>
            <goal>stop</goal>
          </goals>
          <id>stop</id>
          <phase>post-integration-test</phase>
        </execution>
      </executions>
      <groupId>org.springframework.boot</groupId>
      <version>3.0.6</version>
    </plugin>
    <plugin>
      <artifactId>ijhttp-maven-plugin</artifactId>
      <configuration>
        <executable>${project.build.directory}/ijhttp/ijhttp</executable>
        <files>
          <file>your-test-requests.http</file>
        </files>
        <report>true</report>
      </configuration>
      <executions>
        <execution>
          <goals>
            <goal>run</goal>
          </goals>
          <id>http-test</id>
        </execution>
      </executions>
      <groupId>uk.bot-by.maven-plugin</groupId>
      <version>1.0.0</version>
    </plugin>
  </plugins>
</build>

На цьому можно було б завершити, адже це рішення працює будь де. Але, вже більше з цікавості, захотілось зробити «нативні» рішення для GitLab та GitHub.

GitLab

Почну з улюбленої платформи. Тут все дуже просто: додаємо таск, в якому скачується HTTP Client та запускається етап інтеграційних тестів. В проєкті Maven потрібні всі плагіни, крім download-maven-plugin, приклади наведені вище.

http-test:
  stage: test
  script:
    - microdnf install unzip
    - curl -f -s -L -o ijhttp.zip https://jb.gg/ijhttp/latest
    - unzip -nq ijhttp.zip -d target
    - unzip -nq ijhttp.zip -d target
    - rm ijhttp.zip
    - mvn $MAVEN_CLI_OPTS verify
  artifacts:
    reports:
      junit:
        - reports/report.xml

GitHub

У workflow так само додаємо кроки для скачування HTTP Client та запуску інтеграційних тестів.

❗️ До слова, забув сказати, що HTTP Client працює тільки з JDK 17 та вище.

steps:
- uses: actions/checkout@v3
- name: Download ijhttp
  run: curl -f -s -L -o ijhttp.zip https://jb.gg/ijhttp/latest
- name: Unpack ijhttp
  run: unzip -nq ijhttp.zip -d target
- name: Remove ijhttp.zip
  run: rm ijhttp.zip
- name: Set up JDK 17
  uses: actions/setup-java@v3
with:
    java-version: '17'
    distribution: 'temurin'
    cache: maven
- name: Build with Maven
  run: mvn verify

На завершення

Можливо, все що тут написано — це банальщина, але мені закортіло цим знанням поділитися.

Як казав на початку, я писав статтю з прицілом на девелоперів. На мою думку, HTTP Client може бути корисним або для швидкого тестування відомих кейсів, навіть якщо в команді є окремі тестери, або для тестування сервісу у випадку, якщо все тестування покладається на самих розробників, як це, наприклад, зроблено у Flix (проходив там нещодавно співбесіду).

Було б добре ще реалізувати підтримку HTTP Client у вигляді плагіна для Gradle, бо на останніх проєктах переважно використовувася він, а не Maven. Зроблю це, мабуть, трохи згодом.

👍ПодобаєтьсяСподобалось5
До обраногоВ обраному6
LinkedIn
Дозволені теги: blockquote, a, pre, code, ul, ol, li, b, i, del.
Ctrl + Enter
Дозволені теги: blockquote, a, pre, code, ul, ol, li, b, i, del.
Ctrl + Enter

Підкинув колега з Португалії ідею: зробити можливим запуск тестів разом з Spring Boot Test тестуванням. Тобто без малювання конгірурації Maven плагіна яку багато хто не любить надавая перевагу Gradle.
Щось таке я хотів з самого початку, але зміг сформулуювати рішення лише ось недавно.

Тепер запускати тести можна так само як це робиться за допомогою інших інструментів. Стаття яка мене власне надихнула це Spring Boot Testing: MockMvc vs. WebTestClient vs. TestRestTemplate. Конфігурацію можно описати і повністю в application.yaml (чи properties для староверів), так і вручну.

В HTTP Client додані деякі можливості, вони тепер підтрумуються і у Maven плагін і в Spring Boot Test автоконфігурації:
* тепер можна вказати путь до паки в яку пишеться report.xml (але само ім’я файла змінити неможна);
* також можна задати проксі, підтрумується HTTP(S) та SOCKS.

В планах додати можливість вказати папку з http-файлами щоб не додавати кожний окремо. В самому HTTP Client такої можливості немає, тож це буде маленька перевага.

Дякую, крутилося в голові, хоча стек інший, але завдяки статті наґуґлив

python3 -m pip install httpie

тепер можу тестувати логін в мій додаток Flask з коректним токеном і з некоректним, далі розвивати думку щодо інших тестів

http -f POST http://127.0.0.1:38080/login token="some_token"

На HTTP Client теж можна подивитись бо його можна запускати з докер-іміджу.
В статті я це опустив бо спішив поділитись, а вже потім розбирався з докером теж. Може якщо запускати на своїй машині то не дуже зручно, а от десь у CI навпаки дуже зручно та ізольовано виходить.

А чим тести за допомогою httpClient краще за тих що йдуть на етапі тестів? За допомогою MovkMvc також можно перевіряти роботу контролерів. Можете пояснити, будь-ласка?

Це інший рівень тестів: вони скоріш системні ніж інтеграційні.
Я в свої прикладах закинув запуск тестів на етап інтеграційних суто через те що у Maven немає окремого етапу системних тестів і ще тому що в моїх прикладах програма проста і не потребує ніяких зовнішніх ресурсів тож її легко підняти під час роботи Maven.
В реальних великих проектах це може бути взагалі поза етапом збірки вже після того як готова програма задеплоєна на test чи stage інстанс.

Відразу додам: це не срібна пуля, це просто ще один інструмент такий як postman, httpie, hurl чи старий добрий curl.

Тести для MockMvc пишуть самі девелопери.
Цей інструмент скоріш одночасно і для QA і для девелоперів. Наприклад тести у вигляді *.http-файлів пишуть QA потім кидають їх в репозиторій, а потім деви можуть прямо у себе на машині (чи запустивши збірку в CI) перевірити що їх код відповідає вимогам тестів.

Мій неідеальний досвід роботи виглядав так: ми пишемо код, свої юніт і деколи інтеграційні тести, пушимо, щось там десь збирається, деплоїться вручну чи якщо пощастить автоматом.
І потім окремо «за свистком» запускаються автоматичні тести чи відбувається тестування «вручну». І вже потім ми отримуємо відгук чи все ОК.
Якщо тести лежать прямо в мене на машині мені не треба проходити все це, я можу запустити їх після внесення змін і якщо щось пішло не так відразу продебажити та виправити.
Звісно все це я можу зробити і за допомогою звичайних юніт та інтеграційних тестів. Але ж нащо нам тоді QA якщо ми самі все чудово тестуємо? ;)

Окремий випадок коли програма чомусь не використовує Spring і тому тести з MockMvc відпадають. Наприклад це щось що працює на базі старого e-commerce фреймворка з трьох букв.

Ще одна причина чому мене ця ідея «запечила».
На останньому проекті наша мікросервіс був клієнтом іншого веб-сервісу і хоч в нас був тестовий доступ до його копії але працювала вона повільно (деколи тести падали через це). Також там не було даних які були потрібні нашим тестерам, а внесення нових було довгим процесом.
Ми з командою знайшли Mock Server www.mock-server.com який крім того що може бути запущений окремо, можно також запускати на етапі інтеграційних тестів. Чим ми і скористались: разом з тестерами зробили тестову конфігурації з потрібними даними і потім використовували це і інтеграційних тестах, а QA-команда прогоняла свої тести против окремо піднятого мока веб-сервісу.
А HTTP Client будучи так би мовити антагоністом по відношенню до Mock-Server надає можливість закрити іншу половину задач якщо програма сама є веб-сервісом. В нас на проекті замість цього ми користувались купкою bash-скриптів які через curl робили запити. Але все це не читабильне, його не зручно використовувати одночасно і з localhost, і для тестів dev/test-інстанса, складно зробити так щоб відпрацювали все запити бо скрипт падає після першої неправильної відповіді.

Ще є варіант з використанням Docker образу jetbrains/intellij-http-client, але я його не розглядав.

Був вільний час, вирішив нашвидкоруч розібратись і з цим.

В демо-проекті додані приклади запуску HTTP Client з образу наданого Jetbrains. Приклади може не ідеальні, але в цілому демонструють можливість тестуванння навіть для проектів які не базуються на java.

Підписатись на коментарі