𝗦𝗽𝗿𝗶𝗻𝗴 𝗕𝗼𝗼𝘁 𝗧𝗲𝘀𝘁𝗝𝗮𝗿𝘀, або викинь 𝗗𝗼𝗰𝗸𝗲𝗿 для написання інтеграційних тестів!

Пролог

Южуал девелопер у 25 років

Усміхаєшся, коли чуєш “інтеграційні тести”? Ну звісно: знову треба піднімати десяток сервісів у Docker, а лептоп при цьому перетворюється на обігрівач, усе гальмує, шумить і гріється.

А що як я скажу, що є альтернатива Docker? 🤔

Ще у 2024 році Josh Long презентував Spring Boot Testjars — експериментальну фічу, яка дозволяє запускати Spring Boot-додатки прямо з Java-тестів. Без Docker. Круто? Ще б пак! Але не все так ідеально — Testjars ще в експериментальній фазі, не вистачає багатьох речей, але основне вже працює, і це відкриває цікаві можливості.

Епіграф

Я, натхненний цією ідеєю, написав невеличкий pet-проєкт, щоб показати, як Testjars працює на практиці.

Маю два сервіси:

  • 📚 bookshelf — простий CRUD-додаток, який буде запускатись як окремий jar у тестах;

  • 🔁 demotestjars — сервіс-проксі до bookshelf, який використовує Feign-клієнт для взаємодії.

Як це працює

Спершу нам треба зібрати bookshelf як .jar, придатний для запуску з тестів. Просто зарань mvn clean install 😊

Крок 1: Додаємо залежності

<dependency>
  <groupId>org.springframework.experimental.boot</groupId>
  <artifactId>spring-boot-testjars</artifactId>
  <version>0.0.4</version>
  <scope>test</scope>
</dependency>

 <dependency>
  <groupId>org.springframework.experimental.boot</groupId>
  <artifactId>spring-boot-testjars-maven</artifactId>
  <version>0.0.4</version>
</dependency>

Крок 2: Створюємо проперті файл для bookshelf

server.port=18083

spring.datasource.url=jdbc:h2:tcp://localhost:9092/mem:bookshelf
spring.datasource.driver-class-name=org.h2.Driver
spring.datasource.username=sa
spring.datasource.password=

spring.jpa.hibernate.ddl-auto=none
spring.jpa.show-sql=true
spring.jpa.database-platform=org.hibernate.dialect.H2Dialect

💡 Ми використовуємо H2 замість реальної БД — якраз реальний кейс з життя

Крок 3: Конфігуруємо запуск bookshelf у тестах

  @Bean
  static CommonsExecWebServerFactoryBean bookShelfServer() {
    return CommonsExecWebServerFactoryBean.builder()
        .useRandomPort(false)
        .classpath(cp -> cp
            .entries(
                new MavenClasspathEntry("com.example:bookshelf:0.0.1-SNAPSHOT"),
                new MavenClasspathEntry("com.h2database:h2:2.3.232"),
                new ResourceClasspathEntry("book-shelf.properties", "application.properties")
                )
        );
  }

І все! Тепер bookshelf запускається як окремий Spring Boot сервіс просто у вашому інтеграційному тесті — без Docker і YAML’ів.

Що бачимо у логах

Коли запускаєш тести, бачиш логи не лише основного застосунку (demotestjars), а й запущеного bookshelf — як у справжньому інтеграційному середовищі. Жодного Docker.

2025-05-11T23:26:05.517+03:00  INFO 4312 --- [demotestjars] [o-auto-1-exec-1] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring DispatcherServlet 'dispatcherServlet'
2025-05-11T23:26:05.518+03:00  INFO 4312 --- [demotestjars] [o-auto-1-exec-1] o.s.web.servlet.DispatcherServlet        : Initializing Servlet 'dispatcherServlet'
2025-05-11T23:26:05.518+03:00  INFO 4312 --- [demotestjars] [o-auto-1-exec-1] o.s.web.servlet.DispatcherServlet        : Completed initialization in 0 ms
2025-05-11T23:26:05.556+03:00 DEBUG 4312 --- [demotestjars] [o-auto-1-exec-1] c.d.demotestjars.client.BookShelfClient  : [BookShelfClient#addBook] ---> POST http://localhost:18083/api/books HTTP/1.1
2025-05-11T23:26:05.556+03:00 DEBUG 4312 --- [demotestjars] [o-auto-1-exec-1] c.d.demotestjars.client.BookShelfClient  : [BookShelfClient#addBook] Content-Length: 78
2025-05-11T23:26:05.556+03:00 DEBUG 4312 --- [demotestjars] [o-auto-1-exec-1] c.d.demotestjars.client.BookShelfClient  : [BookShelfClient#addBook] Content-Type: application/json
2025-05-11T23:26:05.556+03:00 DEBUG 4312 --- [demotestjars] [o-auto-1-exec-1] c.d.demotestjars.client.BookShelfClient  : [BookShelfClient#addBook] 
2025-05-11T23:26:05.556+03:00 DEBUG 4312 --- [demotestjars] [o-auto-1-exec-1] c.d.demotestjars.client.BookShelfClient  : [BookShelfClient#addBook] {"id":null,"title":"Test Driven Development","author":"Kent Beck","year":2003}
2025-05-11T23:26:05.556+03:00 DEBUG 4312 --- [demotestjars] [o-auto-1-exec-1] c.d.demotestjars.client.BookShelfClient  : [BookShelfClient#addBook] ---> END HTTP (78-byte body)
2025-05-11T23:26:05.589+03:00  INFO 4316 --- [bookshelf] [io-18083-exec-1] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring DispatcherServlet 'dispatcherServlet'
2025-05-11T23:26:05.590+03:00  INFO 4316 --- [bookshelf] [io-18083-exec-1] o.s.web.servlet.DispatcherServlet        : Initializing Servlet 'dispatcherServlet'
2025-05-11T23:26:05.590+03:00  INFO 4316 --- [bookshelf] [io-18083-exec-1] o.s.web.servlet.DispatcherServlet        : Completed initialization in 0 ms
2025-05-11T23:26:05.655+03:00  INFO 4316 --- [bookshelf] [io-18083-exec-1] c.example.bookshelf.service.BookService  : save Book: Book(id=null, title=Test Driven Development, author=Kent Beck, year=2003)
Hibernate: insert into book (author,title,created_year,id) values (?,?,?,default)
2025-05-11T23:26:05.736+03:00 DEBUG 4312 --- [demotestjars] [o-auto-1-exec-1] c.d.demotestjars.client.BookShelfClient  : [BookShelfClient#addBook] <--- HTTP/1.1 200 (179ms)
2025-05-11T23:26:05.736+03:00 DEBUG 4312 --- [demotestjars] [o-auto-1-exec-1] c.d.demotestjars.client.BookShelfClient  : [BookShelfClient#addBook] connection: keep-alive
2025-05-11T23:26:05.736+03:00 DEBUG 4312 --- [demotestjars] [o-auto-1-exec-1] c.d.demotestjars.client.BookShelfClient  : [BookShelfClient#addBook] content-type: application/json
2025-05-11T23:26:05.736+03:00 DEBUG 4312 --- [demotestjars] [o-auto-1-exec-1] c.d.demotestjars.client.BookShelfClient  : [BookShelfClient#addBook] date: Sun, 11 May 2025 20:26:05 GMT
2025-05-11T23:26:05.736+03:00 DEBUG 4312 --- [demotestjars] [o-auto-1-exec-1] c.d.demotestjars.client.BookShelfClient  : [BookShelfClient#addBook] keep-alive: timeout=60
2025-05-11T23:26:05.736+03:00 DEBUG 4312 --- [demotestjars] [o-auto-1-exec-1] c.d.demotestjars.client.BookShelfClient  : [BookShelfClient#addBook] transfer-encoding: chunked
2025-05-11T23:26:05.736+03:00 DEBUG 4312 --- [demotestjars] [o-auto-1-exec-1] c.d.demotestjars.client.BookShelfClient  : [BookShelfClient#addBook] 
2025-05-11T23:26:05.737+03:00 DEBUG 4312 --- [demotestjars] [o-auto-1-exec-1] c.d.demotestjars.client.BookShelfClient  : [BookShelfClient#addBook] {"id":1,"title":"Test Driven Development","author":"Kent Beck","year":2003}
2025-05-11T23:26:05.737+03:00 DEBUG 4312 --- [demotestjars] [o-auto-1-exec-1] c.d.demotestjars.client.BookShelfClient  : [BookShelfClient#addBook] <--- END HTTP (75-byte body)
2025-05-11T23:26:05.782+03:00 DEBUG 4312 --- [demotestjars] [o-auto-1-exec-2] c.d.demotestjars.client.BookShelfClient  : [BookShelfClient#getAllBooks] ---> GET http://localhost:18083/api/books HTTP/1.1
2025-05-11T23:26:05.782+03:00 DEBUG 4312 --- [demotestjars] [o-auto-1-exec-2] c.d.demotestjars.client.BookShelfClient  : [BookShelfClient#getAllBooks] ---> END HTTP (0-byte body)
2025-05-11T23:26:05.784+03:00  INFO 4316 --- [bookshelf] [io-18083-exec-2] c.example.bookshelf.service.BookService  : get All Books
Hibernate: select b1_0.id,b1_0.author,b1_0.title,b1_0.created_year from book b1_0
2025-05-11T23:26:05.850+03:00 DEBUG 4312 --- [demotestjars] [o-auto-1-exec-2] c.d.demotestjars.client.BookShelfClient  : [BookShelfClient#getAllBooks] <--- HTTP/1.1 200 (67ms)
2025-05-11T23:26:05.850+03:00 DEBUG 4312 --- [demotestjars] [o-auto-1-exec-2] c.d.demotestjars.client.BookShelfClient  : [BookShelfClient#getAllBooks] connection: keep-alive
2025-05-11T23:26:05.850+03:00 DEBUG 4312 --- [demotestjars] [o-auto-1-exec-2] c.d.demotestjars.client.BookShelfClient  : [BookShelfClient#getAllBooks] content-type: application/json
2025-05-11T23:26:05.850+03:00 DEBUG 4312 --- [demotestjars] [o-auto-1-exec-2] c.d.demotestjars.client.BookShelfClient  : [BookShelfClient#getAllBooks] date: Sun, 11 May 2025 20:26:05 GMT
2025-05-11T23:26:05.850+03:00 DEBUG 4312 --- [demotestjars] [o-auto-1-exec-2] c.d.demotestjars.client.BookShelfClient  : [BookShelfClient#getAllBooks] keep-alive: timeout=60
2025-05-11T23:26:05.850+03:00 DEBUG 4312 --- [demotestjars] [o-auto-1-exec-2] c.d.demotestjars.client.BookShelfClient  : [BookShelfClient#getAllBooks] transfer-encoding: chunked
2025-05-11T23:26:05.850+03:00 DEBUG 4312 --- [demotestjars] [o-auto-1-exec-2] c.d.demotestjars.client.BookShelfClient  : [BookShelfClient#getAllBooks] 
2025-05-11T23:26:05.850+03:00 DEBUG 4312 --- [demotestjars] [o-auto-1-exec-2] c.d.demotestjars.client.BookShelfClient  : [BookShelfClient#getAllBooks] [{"id":1,"title":"Test Driven Development","author":"Kent Beck","year":2003}]
2025-05-11T23:26:05.850+03:00 DEBUG 4312 --- [demotestjars] [o-auto-1-exec-2] c.d.demotestjars.client.BookShelfClient  : [BookShelfClient#getAllBooks] <--- END HTTP (77-byte body)
2025-05-11T23:26:05.903+03:00  INFO 4312 --- [demotestjars] [ionShutdownHook] o.s.b.w.e.tomcat.GracefulShutdown        : Commencing graceful shutdown. Waiting for active requests to complete
2025-05-11T23:26:05.905+03:00  INFO 4312 --- [demotestjars] [tomcat-shutdown] o.s.b.w.e.tomcat.GracefulShutdown        : Graceful shutdown complete
2025-05-11T23:26:05.906+03:00  INFO 4312 --- [demotestjars] [ionShutdownHook] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Shutdown initiated...
2025-05-11T23:26:05.911+03:00  INFO 4312 --- [demotestjars] [ionShutdownHook] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Shutdown completed.

Мінуси (поки що)

Testjars має потенціал, але поки не все працює як хочеться:

1. Не працює анотація @DynamicProperty

Ця фіча також є в документації, але в реальному житті вона поки що не працює. Подробиці:
https://github.com/spring-projects-experimental/spring-boot-testjars?tab=readme-ov-file#dynamicproperty

Епілог

Чи зможе Testjars замінити Docker? Повноцінно — ні. Адже Postgres, Oracle чи Redis у вигляді jar-файлів ти не запустиш. Але якщо тобі треба інтегрувати лише власні мікросервіси — це класне рішення.

Особливо, якщо ти працюєш на віртуалці або слабкому ноуті, де Docker — це біль.

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

🔗 Посилання на репозиторії:

Хочеш мене підтримати підписуйся на мій патреон:

https://www.patreon.com/c/serhiibarabash

Список джерел
  1. Spring Tips: Spring Boot Testjars
Поділись своїми ідеями в новій публікації.
Ми чекаємо саме на твій довгочит!
Сергій Барабаш
Сергій Барабаш@sbarabash

582Прочитань
1Автори
12Читачі
На Друкарні з 30 березня

Більше від автора

Вам також сподобається

Коментарі (0)

Підтримайте автора першим.
Напишіть коментар!

Вам також сподобається