You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

求指导编写JdbcTemplate查询方法的JUnit测试用例

如何为JdbcTemplate的两个方法编写JUnit测试用例?

我需要为以下两个JdbcTemplate查询方法编写JUnit测试用例,但毫无头绪。已尝试搜索相关方案,未找到合适的解决办法,恳请各位提供帮助。

方法1:

public int savePreBookDetails(String orderId, String preBookAmount, String prodId, String status, String userName, String locationId) {
        KeyHolder keyHolder = new GeneratedKeyHolder();
        try {
            jdbcTemplate.update(connection -> {
                PreparedStatement ps = connection.prepareStatement(insertOrder, Statement.RETURN_GENERATED_KEYS);
                ps.setInt(1, Integer.parseInt(prodId));
                ps.setDouble(2, Double.parseDouble(preBookAmount));
                ps.setString(3, userName);
                ps.setString(4, status);
                ps.setInt(5, Integer.parseInt(locationId));
                ps.setString(6, orderId);
                return ps;
            }, keyHolder);
        } catch (Exception e) {
            LOGGER.error("Error during saving prebook with prodId {} and locationId {} ", prodId,locationId + e);
            throw e;
        }
        return (int) keyHolder.getKeys().get("id");
    }

方法2:

public String findPreBookAmountByOrderId(String orderId) {
        try {
            List<String> list = jdbcTemplate.query(findPreBookAmountByOrderId, (rs, rowNum) -> rs.getString("preBookAmount"), orderId);
            LOGGER.info("Executed query : " + findPreBookAmountByOrderId);
            return list.isEmpty() ? null : list.get(0);
        } catch (Exception e) {
            LOGGER.warn("Error in finding the preBookAmount of orderId {}", orderId + e);
            return null;
        }
    }

解决方案

一、单元测试(用Mockito模拟JdbcTemplate)

这种方式不需要真实数据库,专注于验证方法逻辑和参数传递是否正确。

测试方法1(savePreBookDetails)

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;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.support.GeneratedKeyHolder;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.Statement;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.*;

@ExtendWith(MockitoExtension.class)
public class PreBookDaoTest {

    @Mock
    private JdbcTemplate jdbcTemplate;

    @InjectMocks
    private PreBookDao preBookDao; // 替换成你的DAO类名

    @Test
    void savePreBookDetails_ShouldReturnGeneratedId() throws Exception {
        // 测试数据
        String orderId = "ORD123";
        String preBookAmount = "100.50";
        String prodId = "101";
        String status = "SUCCESS";
        String userName = "user1";
        String locationId = "5";
        int expectedId = 1;

        // 模拟数据库连接和预处理语句
        Connection mockConn = mock(Connection.class);
        PreparedStatement mockPs = mock(PreparedStatement.class);
        when(mockConn.prepareStatement(any(String.class), eq(Statement.RETURN_GENERATED_KEYS))).thenReturn(mockPs);

        // 模拟JdbcTemplate的update行为,设置返回的自增ID
        doAnswer(invocation -> {
            GeneratedKeyHolder keyHolder = invocation.getArgument(1);
            keyHolder.getKeys().put("id", expectedId);
            return 1; // 返回受影响行数
        }).when(jdbcTemplate).update(any(), any(GeneratedKeyHolder.class));

        // 执行测试
        int actualId = preBookDao.savePreBookDetails(orderId, preBookAmount, prodId, status, userName, locationId);

        // 验证结果
        assertEquals(expectedId, actualId);
        // 验证参数是否正确设置到预处理语句
        verify(mockPs).setInt(1, Integer.parseInt(prodId));
        verify(mockPs).setDouble(2, Double.parseDouble(preBookAmount));
        verify(mockPs).setString(3, userName);
        verify(mockPs).setString(4, status);
        verify(mockPs).setInt(5, Integer.parseInt(locationId));
        verify(mockPs).setString(6, orderId);
    }

    @Test
    void savePreBookDetails_ShouldThrowException_WhenParsingFails() {
        // 传入无效的数值字符串,预期抛出格式异常
        String invalidProdId = "abc";

        assertThrows(NumberFormatException.class, () -> {
            preBookDao.savePreBookDetails("ORD123", "100.50", invalidProdId, "SUCCESS", "user1", "5");
        });
    }
}

测试方法2(findPreBookAmountByOrderId)

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;
import org.springframework.jdbc.core.JdbcTemplate;
import java.util.Collections;
import java.util.List;
import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.ArgumentMatchers.*;
import static org.mockito.Mockito.when;

@ExtendWith(MockitoExtension.class)
public class PreBookDaoTest {

    @Mock
    private JdbcTemplate jdbcTemplate;

    @InjectMocks
    private PreBookDao preBookDao;

    @Test
    void findPreBookAmountByOrderId_ShouldReturnAmount_WhenExists() {
        String orderId = "ORD123";
        String expectedAmount = "100.50";

        when(jdbcTemplate.query(anyString(), any(), eq(orderId))).thenReturn(List.of(expectedAmount));

        String actualAmount = preBookDao.findPreBookAmountByOrderId(orderId);
        assertEquals(expectedAmount, actualAmount);
    }

    @Test
    void findPreBookAmountByOrderId_ShouldReturnNull_WhenNoResult() {
        String orderId = "ORD999";

        when(jdbcTemplate.query(anyString(), any(), eq(orderId))).thenReturn(Collections.emptyList());

        String actualAmount = preBookDao.findPreBookAmountByOrderId(orderId);
        assertNull(actualAmount);
    }

    @Test
    void findPreBookAmountByOrderId_ShouldReturnNull_WhenExceptionOccurs() {
        String orderId = "ORD123";

        when(jdbcTemplate.query(anyString(), any(), eq(orderId))).thenThrow(new RuntimeException("DB Error"));

        String actualAmount = preBookDao.findPreBookAmountByOrderId(orderId);
        assertNull(actualAmount);
    }
}

二、集成测试(用H2嵌入式数据库)

这种方式使用内存数据库,验证真实的SQL执行和数据交互逻辑。

步骤1:添加测试依赖(Maven)

<dependency>
    <groupId>com.h2database</groupId>
    <artifactId>h2</artifactId>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test</artifactId>
    <scope>test</scope>
</dependency>

步骤2:配置测试环境(application-test.properties)

spring.datasource.url=jdbc:h2:mem:testdb;DB_CLOSE_DELAY=-1
spring.datasource.driverClassName=org.h2.Driver
spring.datasource.username=sa
spring.datasource.password=
spring.jpa.hibernate.ddl-auto=create-drop

步骤3:初始化表结构(src/test/resources/schema.sql)

CREATE TABLE pre_book (
    id INT AUTO_INCREMENT PRIMARY KEY,
    prod_id INT,
    pre_book_amount DOUBLE,
    user_name VARCHAR(255),
    status VARCHAR(50),
    location_id INT,
    order_id VARCHAR(255) UNIQUE
);

步骤4:编写集成测试类

import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.ActiveProfiles;
import static org.junit.jupiter.api.Assertions.*;

@SpringBootTest
@ActiveProfiles("test")
public class PreBookDaoIntegrationTest {

    @Autowired
    private PreBookDao preBookDao;

    @Test
    void saveAndFindPreBookDetails_ShouldWorkCorrectly() {
        // 插入测试数据
        String orderId = "ORD_INTEG_001";
        String preBookAmount = "200.75";
        String prodId = "202";
        String status = "PENDING";
        String userName = "testUser";
        String locationId = "10";

        int generatedId = preBookDao.savePreBookDetails(orderId, preBookAmount, prodId, status, userName, locationId);
        assertTrue(generatedId > 0);

        // 查询验证
        String foundAmount = preBookDao.findPreBookAmountByOrderId(orderId);
        assertEquals(preBookAmount, foundAmount);

        // 查询不存在的订单
        String notFoundAmount = preBookDao.findPreBookAmountByOrderId("ORD_NOT_EXIST");
        assertNull(notFoundAmount);
    }
}

内容的提问来源于stack exchange,提问作者Sarwar Akbar

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.23 01:42:23