When you have 200 concurrent users hitting a single-threaded service, you’ll see the connection pool exhaustion error: “java.sql.SQLException: Connection is closed”. This is because the default connection pool size is not sufficient to handle the load. To fix this, you need to implement proper testing using JUnit and Mockito.

TL;DR: In this tutorial, you will learn how to implement unit tests and integration tests for Spring Boot applications using JUnit and Mockito. You will also learn how to fix common mistakes and optimize performance.

## PREREQUISITES * Java 17 or later * Spring Boot 2.7 or later * Maven 3.8 or later or Gradle 7.4 or later * JUnit 5.8 or later * Mockito 4.11 or later The following Maven dependency block is required:

 <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>org.junit.jupiter</groupId> <artifactId>junit-jupiter-api</artifactId> <version>5.8.2</version> <scope>test</scope> </dependency> <dependency> <groupId>org.mockito</groupId> <artifactId>mockito-junit-jupiter</artifactId> <version>4.11.0</version> <scope>test</scope> </dependency> </dependencies> 

## SPRING BOOT TESTING ARCHITECTURE The Spring Boot testing architecture consists of the following components:

 +---------------+ | Application | +---------------+ | | v +---------------+ | Service Layer | +---------------+ | | v +---------------+ | Repository Layer | +---------------+ | | v +---------------+ | Database | +---------------+ 

The following table compares the different testing frameworks:

Framework Description
JUnit A unit testing framework for Java
Mockito A mocking framework for Java
Spring Boot Test A testing framework for Spring Boot applications

## STEP-BY-STEP IMPLEMENTATION ### Step 1: Create a Spring Boot Application Create a new Spring Boot application using the Spring Initializr:

 package com.example.app; 
 import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; 
 @SpringBootApplication public class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); } } 

### Step 2: Add Dependencies Add the following dependencies to your `pom.xml` file:

 <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>org.junit.jupiter</groupId> <artifactId>junit-jupiter-api</artifactId> <version>5.8.2</version> <scope>test</scope> </dependency> <dependency> <groupId>org.mockito</groupId> <artifactId>mockito-junit-jupiter</artifactId> <version>4.11.0</version> <scope>test</scope> </dependency> </dependencies> 

### Step 3: Create a Service Layer Create a new service layer:

 package com.example.app.service; 
 import org.springframework.stereotype.Service; 
 @Service public class UserService { public String getUser() { return "John Doe"; } } 

### Step 4: Create a Repository Layer Create a new repository layer:

 package com.example.app.repository; 
 import org.springframework.stereotype.Repository; 
 @Repository public class UserRepository { public String getUser() { return "John Doe"; } } 

The expected output is:

 John Doe 

## COMPLETE WORKING EXAMPLE The following is a complete working example:

 package com.example.app; 
 import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; 
 @SpringBootApplication public class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); } } 

The file structure is as follows:

 com.example.app Application.java service UserService.java repository UserRepository.java 

You can test the application using the following curl request:

 curl -X GET http://localhost:8080/user 

The response is:

 John Doe 

## COMMON MISTAKES AND HOW TO FIX THEM ### Mistake 1: Not Closing the Connection Pool The following code does not close the connection pool:

 package com.example.app.service; 
 import org.springframework.stereotype.Service; 
 @Service public class UserService { public String getUser() { // WRONG - causes connection pool exhaustion Connection connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/db", "user", "password"); Statement statement = connection.createStatement(); ResultSet resultSet = statement.executeQuery("SELECT * FROM users"); // ... } } 

The error message is:

 java.sql.SQLException: Connection is closed 

The fixed code is:

 package com.example.app.service; 
 import org.springframework.stereotype.Service; 
 @Service public class UserService { public String getUser() { Connection connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/db", "user", "password"); try { Statement statement = connection.createStatement(); ResultSet resultSet = statement.executeQuery("SELECT * FROM users"); // ... } finally { connection.close(); } } } 

## PERFORMANCE AND PRODUCTION TIPS

Production tip: Use a connection pool to improve performance. Set the spring.datasource.hikari.maximum-pool-size property to 10 for a 4-core server.

Production tip: Use caching to improve performance. Set the spring.cache.type property to redis to use Redis as the cache store.

For more information on Java Algorithms and Mastering SQL, please visit our Java Tutorials page. ## TESTING The following is an example of a JUnit test for the `UserService` class:

 package com.example.app.service; 
 import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; 
 @ExtendWith(MockitoExtension.class) public class UserServiceTest { @Mock private UserRepository userRepository; 
 @InjectMocks private UserService userService; 
 @Test public void testGetUser() { // given when(userRepository.getUser()).thenReturn("John Doe"); 
 // when String user = userService.getUser(); 
 // then assertEquals("John Doe", user); } } 

For more information on Java Interview Questions, please visit our website. ## KEY TAKEAWAYS * Use JUnit and Mockito to write unit tests and integration tests for Spring Boot applications * Use a connection pool to improve performance * Use caching to improve performance * Use Redis as the cache store * Use the spring.datasource.hikari.maximum-pool-size property to set the maximum pool size * Use the spring.cache.type property to set the cache type * Use the @Mock annotation to mock dependencies * Use the @InjectMocks annotation to inject mocks into the service layer

Read Next

Pillar Guide: Java Tutorials Hub — explore the full learning path.

Source Code on GitHub
java-examples — Clone, Star & Contribute

You Might Also Like

Mastering Spring Boot Unit Testing with JUnit 5 and Mockito
Implementing Spring Security with Custom UserDetailsService and Database Integration
Spring Batch Chunk Processing Explained with Examples


Leave a Reply

Your email address will not be published. Required fields are marked *