diff --git a/persistence-modules/core-java-persistence-4/pom.xml b/persistence-modules/core-java-persistence-4/pom.xml
index 801ed4bfa137..264183f23cb4 100644
--- a/persistence-modules/core-java-persistence-4/pom.xml
+++ b/persistence-modules/core-java-persistence-4/pom.xml
@@ -47,6 +47,13 @@
spring-boot-starter
${springframework.boot.spring-boot-starter.version}
+
+
+ org.mockito
+ mockito-junit-jupiter
+ 5.16.0
+ test
+
diff --git a/persistence-modules/core-java-persistence-4/src/main/java/com/baeldung/jdbc/mocking/Customer.java b/persistence-modules/core-java-persistence-4/src/main/java/com/baeldung/jdbc/mocking/Customer.java
new file mode 100644
index 000000000000..55bda68b3d68
--- /dev/null
+++ b/persistence-modules/core-java-persistence-4/src/main/java/com/baeldung/jdbc/mocking/Customer.java
@@ -0,0 +1,8 @@
+package com.baeldung.jdbc.mocking;
+
+public record Customer(int id, String name, Status status) {
+
+ public enum Status {
+ ACTIVE, LOYAL, INACTIVE
+ }
+}
\ No newline at end of file
diff --git a/persistence-modules/core-java-persistence-4/src/main/java/com/baeldung/jdbc/mocking/CustomersService.java b/persistence-modules/core-java-persistence-4/src/main/java/com/baeldung/jdbc/mocking/CustomersService.java
new file mode 100644
index 000000000000..8906bf78cd5d
--- /dev/null
+++ b/persistence-modules/core-java-persistence-4/src/main/java/com/baeldung/jdbc/mocking/CustomersService.java
@@ -0,0 +1,45 @@
+package com.baeldung.jdbc.mocking;
+
+import java.sql.Connection;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Statement;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.sql.DataSource;
+
+import com.baeldung.jdbc.mocking.Customer.Status;
+
+public class CustomersService {
+
+ private final DataSource dataSource;
+
+ public CustomersService(DataSource dataSource) {
+ this.dataSource = dataSource;
+ }
+
+ public List customersEligibleForOffers() throws SQLException {
+ try (Connection conn = dataSource.getConnection(); Statement stmt = conn.createStatement()) {
+ ResultSet resultSet = stmt.executeQuery("SELECT * FROM customers");
+ List customers = new ArrayList<>();
+
+ while (resultSet.next()) {
+ Customer customer = mapCustomer(resultSet);
+ if (customer.status() == Status.ACTIVE || customer.status() == Status.LOYAL) {
+ customers.add(customer);
+ }
+ }
+ return customers;
+ }
+ }
+
+ private Customer mapCustomer(ResultSet resultSet) throws SQLException {
+ return new Customer(
+ resultSet.getInt("id"),
+ resultSet.getString("name"),
+ Status.valueOf(resultSet.getString("status"))
+ );
+ }
+
+}
\ No newline at end of file
diff --git a/persistence-modules/core-java-persistence-4/src/main/java/com/baeldung/jdbc/mocking/v2/AllCustomers.java b/persistence-modules/core-java-persistence-4/src/main/java/com/baeldung/jdbc/mocking/v2/AllCustomers.java
new file mode 100644
index 000000000000..022b7cabe78c
--- /dev/null
+++ b/persistence-modules/core-java-persistence-4/src/main/java/com/baeldung/jdbc/mocking/v2/AllCustomers.java
@@ -0,0 +1,41 @@
+package com.baeldung.jdbc.mocking.v2;
+
+import java.sql.Connection;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Statement;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.function.Supplier;
+
+import javax.sql.DataSource;
+
+import com.baeldung.jdbc.mocking.Customer;
+
+public class AllCustomers implements Supplier> {
+
+ private final DataSource dataSource;
+
+ @Override
+ public List get() {
+ try (Connection conn = dataSource.getConnection(); Statement stmt = conn.createStatement()) {
+ ResultSet resultSet = stmt.executeQuery("SELECT * FROM customers");
+ List customers = new ArrayList<>();
+ while (resultSet.next()) {
+ customers.add(mapCustomer(resultSet));
+ }
+ return customers;
+ } catch (SQLException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ public AllCustomers(DataSource dataSource) {
+ this.dataSource = dataSource;
+ }
+
+ private Customer mapCustomer(ResultSet resultSet) throws SQLException {
+ return new Customer(resultSet.getInt("id"), resultSet.getString("name"), Customer.Status.valueOf(resultSet.getString("status")));
+ }
+
+}
\ No newline at end of file
diff --git a/persistence-modules/core-java-persistence-4/src/main/java/com/baeldung/jdbc/mocking/v2/CustomersServiceV2.java b/persistence-modules/core-java-persistence-4/src/main/java/com/baeldung/jdbc/mocking/v2/CustomersServiceV2.java
new file mode 100644
index 000000000000..8ccc7b06cdc1
--- /dev/null
+++ b/persistence-modules/core-java-persistence-4/src/main/java/com/baeldung/jdbc/mocking/v2/CustomersServiceV2.java
@@ -0,0 +1,24 @@
+package com.baeldung.jdbc.mocking.v2;
+
+import java.util.List;
+import java.util.function.Supplier;
+
+import com.baeldung.jdbc.mocking.Customer;
+import com.baeldung.jdbc.mocking.Customer.Status;
+
+public class CustomersServiceV2 {
+
+ private final Supplier> findAllCustomers;
+
+ public List customersEligibleForOffers() {
+ return findAllCustomers.get()
+ .stream()
+ .filter(customer -> customer.status() == Status.ACTIVE || customer.status() == Status.LOYAL)
+ .toList();
+ }
+
+ public CustomersServiceV2(Supplier> findAllCustomers) {
+ this.findAllCustomers = findAllCustomers;
+ }
+
+}
\ No newline at end of file
diff --git a/persistence-modules/core-java-persistence-4/src/test/java/com/baeldung/jdbc/mocking/JdbcMockingIntegrationTest.java b/persistence-modules/core-java-persistence-4/src/test/java/com/baeldung/jdbc/mocking/JdbcMockingIntegrationTest.java
new file mode 100644
index 000000000000..e8c48827ff02
--- /dev/null
+++ b/persistence-modules/core-java-persistence-4/src/test/java/com/baeldung/jdbc/mocking/JdbcMockingIntegrationTest.java
@@ -0,0 +1,36 @@
+package com.baeldung.jdbc.mocking;
+
+import static org.assertj.core.api.AssertionsForInterfaceTypes.assertThat;
+
+import java.sql.SQLException;
+import java.util.List;
+
+import org.h2.jdbcx.JdbcDataSource;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Test;
+
+import com.baeldung.jdbc.mocking.Customer.Status;
+
+class JdbcMockingIntegrationTest {
+
+ private static JdbcDataSource dataSource;
+
+ @BeforeAll
+ static void setUp() {
+ dataSource = new JdbcDataSource();
+ dataSource.setURL("jdbc:h2:mem:testdb;DB_CLOSE_DELAY=-1;INIT=RUNSCRIPT FROM 'classpath:data.sql'");
+ dataSource.setUser("sa");
+ dataSource.setPassword("");
+ }
+
+ @Test
+ void whenFetchingCustomersEligibleForOffers_thenTheyHaveActiveOrLoyalStatus() throws SQLException {
+ CustomersService customersService = new CustomersService(dataSource);
+
+ List customers = customersService.customersEligibleForOffers();
+
+ assertThat(customers).extracting(Customer::status)
+ .containsOnly(Status.ACTIVE, Status.LOYAL);
+ }
+
+}
\ No newline at end of file
diff --git a/persistence-modules/core-java-persistence-4/src/test/java/com/baeldung/jdbc/mocking/JdbcMockingUnitTest.java b/persistence-modules/core-java-persistence-4/src/test/java/com/baeldung/jdbc/mocking/JdbcMockingUnitTest.java
new file mode 100644
index 000000000000..b57ca00a1ecf
--- /dev/null
+++ b/persistence-modules/core-java-persistence-4/src/test/java/com/baeldung/jdbc/mocking/JdbcMockingUnitTest.java
@@ -0,0 +1,76 @@
+package com.baeldung.jdbc.mocking;
+
+import static org.assertj.core.api.AssertionsForInterfaceTypes.assertThat;
+import static org.mockito.Mockito.when;
+
+import java.sql.Connection;
+import java.sql.ResultSet;
+import java.sql.Statement;
+import java.util.List;
+
+import javax.sql.DataSource;
+
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.Mock;
+import org.mockito.junit.jupiter.MockitoExtension;
+
+import com.baeldung.jdbc.mocking.Customer.Status;
+import com.baeldung.jdbc.mocking.v2.CustomersServiceV2;
+
+@ExtendWith(MockitoExtension.class)
+class JdbcMockingUnitTest {
+
+ @Mock
+ DataSource dataSource;
+ @Mock
+ Connection conn;
+ @Mock
+ Statement stmt;
+ @Mock
+ ResultSet resultSet;
+
+ @Test
+ void whenFetchingEligibleCustomers_thenTheyHaveCorrectStatus() throws Exception {
+ //given
+ CustomersService customersService = new CustomersService(dataSource);
+
+ when(dataSource.getConnection())
+ .thenReturn(conn);
+ when(conn.createStatement())
+ .thenReturn(stmt);
+ when(stmt.executeQuery("SELECT * FROM customers"))
+ .thenReturn(resultSet);
+
+ when(resultSet.next())
+ .thenReturn(true, true, true, false);
+ when(resultSet.getInt("id"))
+ .thenReturn(1, 2, 3);
+ when(resultSet.getString("name"))
+ .thenReturn("Alice", "Bob", "John");
+ when(resultSet.getString("status"))
+ .thenReturn("LOYAL", "ACTIVE", "INACTIVE");
+
+ // when
+ List eligibleCustomers = customersService.customersEligibleForOffers();
+
+ // then
+ assertThat(eligibleCustomers).containsExactlyInAnyOrder(new Customer(1, "Alice", Status.LOYAL), new Customer(2, "Bob", Status.ACTIVE));
+ }
+
+ @Test
+ void whenFetchingEligibleCustomersFromV2_thenTheyHaveCorrectStatus() {
+ // given
+ List allCustomers = List.of(new Customer(1, "Alice", Status.LOYAL), new Customer(2, "Bob", Status.ACTIVE),
+ new Customer(3, "John", Status.INACTIVE));
+
+ CustomersServiceV2 service = new CustomersServiceV2(() -> allCustomers);
+
+ // when
+ List eligibleCustomers = service.customersEligibleForOffers();
+
+ // then
+ assertThat(eligibleCustomers).containsExactlyInAnyOrder(new Customer(1, "Alice", Status.LOYAL), new Customer(2, "Bob", Status.ACTIVE));
+ }
+
+}
\ No newline at end of file
diff --git a/persistence-modules/core-java-persistence-4/src/test/resources/data.sql b/persistence-modules/core-java-persistence-4/src/test/resources/data.sql
new file mode 100644
index 000000000000..774a0b55fb6c
--- /dev/null
+++ b/persistence-modules/core-java-persistence-4/src/test/resources/data.sql
@@ -0,0 +1,4 @@
+create table customers (id int primary key, name varchar(255), status varchar(255));
+insert into customers (id, name, status) values (1, 'Alice', 'LOYAL');
+insert into customers (id, name, status) values (2, 'Bob', 'ACTIVE');
+insert into customers (id, name, status) values (3, 'Charlie', 'INACTIVE');
\ No newline at end of file