DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Refcards Trend Reports
Events Video Library
Refcards
Trend Reports

Events

View Events Video Library

Related

  • A Practical Guide to Creating a Spring Modulith Project
  • Be Punctual! Avoiding Kotlin’s lateinit In Spring Boot Testing
  • Distributed Tracing System (Spring Cloud Sleuth + OpenZipkin)
  • Java, Spring Boot, and MongoDB: Performance Analysis and Improvements

Trending

  • Skills, Java 17, and Theme Accents
  • Building Threat Intelligence Pipelines Using Python, APIs, and Elasticsearch
  • How to Parse Large XML Files in PHP Without Running Out of Memory
  • Getting Started With Agentic Workflows in Java and Quarkus
  1. DZone
  2. Coding
  3. Frameworks
  4. Avoid Reloading Application Context on Unit Tests

Avoid Reloading Application Context on Unit Tests

A Zone Leader provides insight on how to cut down on unit test execution time, when mocking related services as part of a unit test.

By 
John Vester user avatar
John Vester
DZone Core CORE ·
Dec. 17, 19 · Tutorial
Likes (9)
Comment
Save
Tweet
Share
67.9K Views

Join the DZone community and get the full member experience.

Join For Free

Learn more about Unit tests!

Glancing through my articles on DZone, one can easily conclude that I am a fan of the Spring Boot framework for RESTful application development. That same query could easily conclude that I am a fan of providing ample unit test coverage for those very same RESTful APIs.

On a recent project, I realized that the use of @MockBean in my unit tests was having a major impact on the execution time for the test phase within our CI/CD pipeline.

This article talks about one way to resolve this issue.

You may also like: Unit Testing: The Good, Bad, and Ugly

@MockBean

The @MockBean annotation will add mock objects into the Spring application context. As a result, the mocked item will replace any existing bean of the same type in the application context. When this happens, Spring Boot realizes the application context has to be reloaded as part of the test initialization.

While this may not seem like a big deal, especially when this is typically a 10-15 second process, it can have an impact on the time to deploy — when there is a large code base to cover.

A Simple Example

Consider this simple service class example.

Java
x
1
@RequiredArgsConstructor
2
@Service
3
public class WidgetServiceImpl implements WidgetService {
4
  private final AccountService accountService;
5
  private final WidgetRepository widgetRepository;
6
  
7
  /**
8
  * {@inheritDoc}
9
  */
10
  @Override
11
  public List<Widget> getWidgetsByAccountId(Long accountId, String authId) throws AccountException {
12
    Account account = accountService.getAccountById(accountId, authId);
13
    return widgetRepository.getWidgetsByAccountId(accountId);
14
  }
15
} 


In the example above, constructor-based injections are being used, via Lombok's @RequiredArgsConstructor annotation, which is why a public constructor does not exist within the code.

For the getWidgetsByAccountId method to succeed, the accountId and authId must be provided to the AccountService in order to return a valid Account. This step is merely to help illustrate my point in the unit tests — when a service is dependent on something else. Basically, the business rule states that the WidgetService needs to interact with the AccountService as part of the request process.

If the AccountService does not throw an AccountException, the WidgetRepository (JPA interface) will simply return a List<Widget> for the provided accountId.

Unit Testing Background

In this example, both the AccountService and WidgetRepository needed to be mocked in order to provide information for the WidgetService...or the system under test (SUT).

I have always been a fan of keeping unit tests focused on the SUT and favor use of mocking over utilizing a database connection — which may or may not always have the data needed for the unit test to work properly.

In the WidgetServiceTest class, the Mockito when() method is utilized to interface with the mocked services and provide simulated results, which are geared to test the SUT.

Some examples may include:

  • Providing the expected Account data to process the results.
  • Providing the expected Widget repository data to process the results.
  • Throwing exceptions to validate the AccountException fires.

By mocking the injected dependencies, the unit tests remain focused on the SUT.

Testing the Simple Example Using @MockBean

With Spring Boot, it is very possible to configure the WidgetServiceTest using @MockBean and @Autowired:

Java




xxxxxxxxxx
1
10


 
1
public class WidgetServiceTest extends BaseServiceTest {
2
  @MockBean
3
  AccountService accountService;
4
  @MockBean
5
  WidgetRepository widgetRespository;
6
  @Autowired
7
  WidgetServiceImpl widgetService;
8
  
9
  ...
10
}



Every service which uses @MockBean for the AccountService will cause the Application Context to be reloaded within Sprint Boot. In my case, this added a 12 second delay before the first test in the class could be executed.

Updating the Simple Example

In the example below, the same service class can be tested without using @MockBean and causing the Application Context to be reloaded:

Java




xxxxxxxxxx
1


 
1
public class WidgetServiceTest extends BaseServiceTest {
2
  private final AccountService accountService = Mockito.mock(AccountService.class);
3
  private final WidgetRepository widgetRespository = Mockito.mock(WidgetRepository.class);
4
  WidgetServiceImpl widgetService = new WidgetService(accountService, widgetRepository);
5
  
6
  ...
7
}



Conclusion

The impact on making this change, ended up resolving issues with the build process and the wait time feature teams had to endure when updates became available for the RESTful API. This led to a faster turnaround time, which had positive impacts on the project's productivity.

There are certainly cases where @MockBean can be employed and not have a negative impact on the unit test process. In the scenario where there are dependencies on other services — which are likely employed by other services — Spring Boot will require the Application Context to be reloaded before the tests can begin. In that case, expect some additional time.

Have a great day!


Further Reading

Best Practices for Writing Unit Tests

Unit Testing Guidelines: What to Test and What Not to Test

Importance of Unit Testing

unit test application Spring Framework System under test Spring Boot

Opinions expressed by DZone contributors are their own.

Related

  • A Practical Guide to Creating a Spring Modulith Project
  • Be Punctual! Avoiding Kotlin’s lateinit In Spring Boot Testing
  • Distributed Tracing System (Spring Cloud Sleuth + OpenZipkin)
  • Java, Spring Boot, and MongoDB: Performance Analysis and Improvements

Partner Resources

×

Comments

The likes didn't load as expected. Please refresh the page and try again.

  • RSS
  • X
  • Facebook

ABOUT US

  • About DZone
  • Support and feedback
  • Community research

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Core Program
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 3343 Perimeter Hill Drive
  • Suite 215
  • Nashville, TN 37211
  • [email protected]

Let's be friends:

  • RSS
  • X
  • Facebook