Efficient Testing for Better Results: Boosting Productivity and Reducing Development Costs

Optimizing slow unit tests isn’t just about saving time—it’s about driving productivity and enhancing development quality. In this article, we explore...

  • Home
  • Blog
  • Efficient Testing for Better R...

Efficient Testing for Better Results: Boosting Productivity and Reducing Development Costs

image

Optimizing slow unit tests isn’t just about saving time—it’s about driving productivity and enhancing development quality.

Listen on Spotify.

In this article, we explore the practical steps taken to reduce test execution time from 15 minutes to just 1 minute. Learn how these optimizations can improve team workflows, minimize costly errors, and ensure faster project delivery. Whether you manage large-scale projects or want to refine your testing processes, these insights will empower your team to achieve more.

Understanding the motivation behind optimizing slow unit tests is crucial. We'll explore the challenges faced by the Client, why we wanted to fix them, and the good things that happened afterward. Expect insights into how faster tests can boost productivity and project success.

Why?

  • 90% reduced project build time
  • 11x faster project build speed
  • 13x faster unit test execution
Blog image | Smitheo

Imagine how this affects a big development team where each team member builds the project several times per day.

Consequences:

  • Slower development
  • Developers locally skip test execution
  • Failing deployments to higher environments

Some Facts Why I did it

  • We like unit/integration testing topics
  • We like to optimize things
  • We prefer Integration over Unit tests
  • Test Diamond > Test Pyramid
  • We don’t like mocks
Blog image | Smitheo


Project

  • AEM Multi-tenant Project
  • Some tenants already live, and some are in development
  • Joined at late stage of the project
  • Code coverage around 60%
  • Unit/Integration tests are not in the best shape
  • 343 test classes
  • 1083 test methods


How to not write Unit Tests

  • Don’t write a test that doesn’t make sense
  • Don’t test if Mockito when() then() methods work correctly
  • Don’t overuse mocking
  • Don’t import and use not needed objects and their methods
Blog image | Smitheo

Blog image | Smitheo

  • Don’t test directly if POJO getters and setters work correctly
  • Don’t write tests just to achieve numbers
Blog image | Smitheo

  • Don’t call external endpoints in unit tests (mock their responses, e.g use Wiremock)
Blog image | Smitheo

Optimization Strategy

Since some projects are already live and multiple development teams are working with the same codebase, the optimization strategy was simple:

  • Only quick wins
  • Minimal code changes
  • Easy code changes
  • Don’t change test code logic
  • Don't change implementation code logic

1. Optimization - Parallel Test Execution for Junit 5

One of the first things that would come to everyone's minds is, let's introduce some concurrency and parallelism. This should speed up the test, but not solve the root cause, and this is just fine for our optimization strategy.

Blog image | Smitheo

What happened:

  • Some tests were failing due to not isolated test context between test cases
  • The test code change was required
  • Execution time didn’t decrease

Optimization

  • Failed

2. Optimization - Easy Code Changes

Optimization

  • Improved test speed execution from ~15 min to ~5 min
  • 3x faster unit test execution

Changes:

  • Removed not needed AemContext object and AemContextExtension
Blog image | Smitheo

  • Removed not needed MockitoExtension and not needed Mockito init(), open() initialization methods
Blog image | Smitheo

  • Replaced @Mock annotations with mock(ClassName.class) method
Blog image | Smitheo

  • Removed not need mocked objects and service registrations
Blog image | Smitheo

  • Converted @BeforeEach to @BeforeAll
Blog image | Smitheo

  • Set appropriate ResourceResolverType in AemContext
Blog image | Smitheo

  • Mock endpoint calls and responses
Blog image | Smitheo

Blog image | Smitheo

3. Optimization – Maven Surefire Plugin & Test Logging Library

Each test was gradually taking more time to execute, meaning that we had potential memory leaks and big CPU activity. We found out that the Test logging library is logging all logs (trace) in memory.

Blog image | Smitheo

Changes:

  • Replaced uk.org.lidalia:slf4j-test with org.slf4j:slf4j-simple
  • Turned off Test Logging

Optimization

  • Improved test speed execution from ~5 min to ~1:30 min
  • 3.3x faster unit test execution

4. Optimization – Maven Surefire Plugin & Forked Test Execution

Since the first try with concurrency and parallelism optimization failed, we were a bit stubborn and started investigating further so we found out that we could execute tests concurrently by configuring the Maven Surefire Plugin.

Blog image | Smitheo

The parameter forkCount defines the maximum number of JVM processes that maven-surefire-plugin will spawn concurrently to execute the tests.

Changes:

  • Set forkCount=2
  • Note: bigger values didn’t bring bigger optimization, potentially can cause build crash on the machine with low resources

Optimization

  • Improved test speed execution from ~1:30 min to ~1 min
  • 1.5x faster unit test execution

5. Bonus tip and final optimization – Maven Daemon

Long story short, Maven Deamon builds maven modules in parallel. If you want to read more about Speeding up the Maven Build time with Maven Daemon, check blog post Testing Behavior, Not Implementation: Building Better Software Faster.

Optimization

  • 90% reduced build time
  • 11x faster project build speed
  • 13x faster unit test execution
Blog image | Smitheo

Conclusion

  • Remove uk.org.lidalia:slf4j-test and turn off or decrease the log level in maven-surefire-plugin: Reduction from ~15 min to ~ 2 min
  • Set forkCount in maven-surefire-plugin for Parallel Test execution: Reduction from ~15 min to ~ 6:40 min
  • Treat your tests and write them as an implementation code (clean, quality, performant): Reduction from ~15 min to ~ 5 min
  • Use additional tools to speed up the development process like Maven Daemon and aemsync

If you want to read more about Unit/Integration Testing, check blog post Testing Behavior, Not Implementation: Building Better Software Faster.

Listen on Spotify.

Want to apply these best practices to your project?

Leverage best practices and tailored solutions to drive success. Contact us today to learn how we can help optimize your Adobe Experience Manager implementation.