How to Build a Test Library for a Microservices-Based Web Application with Geb & Spock

How to Build a Test Library for a Microservices-Based Web Application with Geb & Spock

At REWE digital we are building & maintaining a Microservice based e-commerce web application. Our service teams work quite autonomous & are responsible for their own services' quality. They decide which measures are appropriate & efficient in order ensure no bugs in production. Many have a reasonable code coverage via unit tests, a good lot of service tests –including UI tests– & a sufficient monitoring & alerting system.

However, several teams felt the need for a more integrated testing of the whole system to prevent CSS clashes, errors due to interface changes or eventual inconsistency disasters & many many unforeseen issues.

To support these teams, we decided turn our old retired comprehensive test suite into a test library to enable teams to write their own system tests without the need to implement every stupid step in every team.

In this talk I'd like to present our lessons learned & developed design patterns from implementing such a test library with Geb & Spock.


Michael Kutz

March 30, 2019


  1. @MichaKutz @rewedigital @greachconf How to Build a Test Library for

    a Microservices-Based Web Application with Geb & Spock Madrid, March 30th 2019
  2. @MichaKutz @rewedigital @greachconf

  3. What’s the challenge ?

  4. > 25 teams > 150 services composition of micro-frontends deployment

    at will
  5. None
  6. Simple unit tests are easy Testing a single service is

    easy… but contract tests are hard due to asynchronous communication Fully integrated system tests seem necessary, but are hard ⇒ not done by most teams Requires a test system Requires a built service Requires code only
  7. Each team writes functional test that matter most to them

    Test suite grows bigger and bigger… …test runs take longer and longer Nobody is responsible for the suite as a whole …up to 3 hours!!!
  8. Page Objects for every relevant page Further code to navigate

    around the application Base test class for basic test setup Test environment configuration Test fixtures (accounts, products, addresses) Geb configuration for needed browsers “Hacks” to manipulate the application
  9. How does it work ?

  10. ShopUserActor user = new ShopUserActor(browser, reweConfig) .withPickupMarketSelected() .withInvoiceAddress(Address.COLOGNE) .withRegistered() .withLoggedIn()

    .withWindowSize(1280, 768) def "fill basket"() { given: ShopPage shopPage = shopPage.searchFor("milch") when: shopPage.searchSuggestions.first().addToBasket() then: user.basket.readyForCheckout } Test Actor Test system configuration Basic setup (using hacks) Test fixture Page object Verification via service client
  11. ShopUserActor

  12. Avoid the God pattern with Traits

  13. Page Objects

  14. Abstraction levels Tests use case language Page Objects page structure

    Test Actor workflow language def "fill basket"() { when: user.login() then: user.loggedIn } void logout() { ShopPage shopPage = to ShopPage } class LoginPage extends Page { static url = "/mydata/login" LoginFormModule getLoginForm() { $("form#loginForm") .module(LoginFormModule) } String getErrorMessage() { $(".error-block")?.text() } }
  15. Are we happy ?

  16. • Every single team can easily product high level fully

    integrated system tests • Tests are executed within the CI/CD cycles of the teams and services • Test actor keeps tests very readable & maintainable • Minimized common test suite to monitor test system (service deployments are not the only source of defects!) Conclusion • Teams still need to keep the library up to date when pages or workflows change • Keeping test fixtures in sync with the test system is a huge challenge • Keeping the code base small and maintainable is sometimes hard Good Could be better
  17. Thank You! @MichaKutz @rewedigital @greachconf Please leave feedback at