Spring JdbcTemplate Junit 测试 - ResultSetExtractor/RowMapper

Spring JdbcTemplate Junit 测试覆盖率 - 以 ResultSetExtractor / RowMapper 为例

1、RowMapper Mockito 测试

(1)创建实体类 User

java 复制代码
@Data
public class User {

    private Integer id;

    private String name;

    private String applicant;

    private String address;

    private Boolean flag;
}

(2)JdbcTemplate 业务代码

java 复制代码
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.stereotype.Repository;

import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;

@Repository
public class InsertGroup {

    @Autowired
    JdbcTemplate jdbcTemplate;

    public List<User> getUsers(String sql, String name, String address) {

        return jdbcTemplate.query(sql, new RowMapper<User>() {
            @Override
            public User mapRow(ResultSet rs, int rowNum) throws SQLException {

                User user = new User();
                user.setId(rs.getInt("ID"));
                user.setName(rs.getString("Name"));
                user.setApplicant(rs.getString("Applicant"));
                user.setAddress(rs.getString("Address"));
                user.setFlag(rs.getBoolean("Flag"));
                return user;
            }
        }, name, address);
    }
}

(3)Junit 测试

java 复制代码
package com.example.dao;

import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.*;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.List;

@RunWith(SpringJUnit4ClassRunner.class)
public class InsertGroupTest {

    @Mock
    JdbcTemplate jdbcTemplate;

    @InjectMocks
    InsertGroup insertGroup;

    @Before
    public void init() {
        MockitoAnnotations.openMocks(this);
    }


    @Test
    public void test() {

      /**
         * 需要注意的是:invocation.getArgument(1)
         * jdbcTemplate.query() 中 Mock 的参数索引是以0开始的,RowMapper 是第二个元素,因此索引是 1,如果是第三个位置,那么索引是 2,即 invocation.getArgument(2)
         * 同时需要注意的是,jdbcTemplate 中 query 的方法有很多,但是传的参数是不同的,因此 Mock 的参数数量要根据自己实际用到的 query 参数为准
         */
        Mockito.when(jdbcTemplate.query(
                        ArgumentMatchers.anyString(), ArgumentMatchers.any(RowMapper.class), ArgumentMatchers.any()))
                .thenAnswer((invocation) -> {

                    RowMapper<User> rowMapper = (RowMapper<User>) invocation.getArgument(1);
                    ResultSet rs = Mockito.mock(ResultSet.class);

                    // Mock ResultSet to return one rows.
                    // Mockito.when(rs.getInt(ArgumentMatchers.eq("ID"))).thenReturn(506);

                    // Mock ResultSet to return two rows.
                    Mockito.when(rs.getInt(ArgumentMatchers.eq("ID")))
                            .thenReturn(412, 300);
                    Mockito.when(rs.getString(ArgumentMatchers.eq("Name")))
                            .thenReturn("刘亦菲", "刘诗诗");
                    Mockito.when(rs.getBoolean(ArgumentMatchers.eq("Flag")))
                            .thenReturn(true, false);

                    List<User> users = new ArrayList<>();
                    users.add(rowMapper.mapRow(rs, 0));
                    users.add(rowMapper.mapRow(rs, 1));

                    return users;
                });

        List<User> userList = insertGroup.getUsers("sql", "1", "2");

        // Assert First Row
        assertFirstUser(userList.get(0));

        // Assert Second Row
        assertSecondUser(userList.get(1));
    }

    public void assertFirstUser(User user) {
        Assert.assertEquals(Integer.valueOf(412), user.getId());
        Assert.assertEquals("刘亦菲", user.getName());
        Assert.assertTrue(user.getFlag());
    }

    public void assertSecondUser(User user) {
        Assert.assertEquals(Integer.valueOf(300), user.getId());
        Assert.assertEquals("刘诗诗", user.getName());
        Assert.assertFalse(user.getFlag());
    }
}
2、ResultSetExtractor Mockito 测试

(1)创建 User 实体

java 复制代码
import lombok.Data;

@Data
public class User {

    private Integer id;

    private String name;

    private String applicant;

    private String address;

    private Boolean flag;
}

(2)JdbcTemplate 业务代码

java 复制代码
 public List<User> getUsers2(String sql, String name, String address) {

        return jdbcTemplate.query(sql, new ResultSetExtractor<List<User>>() {
            @Override
            public List<User> extractData(ResultSet rs) throws SQLException, DataAccessException {
                List<User> userList = new ArrayList<>();
                while (rs.next()) {
                    User user = new User();
                    user.setId(rs.getInt("ID"));
                    user.setName(rs.getString("Name"));
                    user.setApplicant(rs.getString("Applicant"));
                    user.setAddress(rs.getString("Address"));
                    user.setFlag(rs.getBoolean("Flag"));
                    userList.add(user);
                }
                return userList;
            }
        }, name, address);
    }

(3)Junit 测试

java 复制代码
 @Test
    public void test2() {
        Mockito.when(jdbcTemplate.query(
                        ArgumentMatchers.anyString(), ArgumentMatchers.any(ResultSetExtractor.class), ArgumentMatchers.any()))
                .thenAnswer((invocation) -> {
                    ResultSetExtractor<List<User>> resultSetExtractor =
                            (ResultSetExtractor<List<User>>) invocation.getArgument(1);

                    ResultSet rs = Mockito.mock(ResultSet.class);

                    // two times it returns true and third time returns false.
                    Mockito.when(rs.next()).thenReturn(true, true, false);

                    // Mock ResultSet to return two rows.
                    Mockito.when(rs.getInt(ArgumentMatchers.eq("ID")))
                            .thenReturn(412, 300);
                    Mockito.when(rs.getString(ArgumentMatchers.eq("Name")))
                            .thenReturn("刘亦菲", "刘诗诗");
                    Mockito.when(rs.getBoolean(ArgumentMatchers.eq("Flag")))
                            .thenReturn(true, false);

                    return resultSetExtractor.extractData(rs);
                });

        List<User> users = insertGroup.getUsers2("sql", "1", "2");

        Assert.assertEquals(Integer.valueOf(412), users.get(0).getId());
        Assert.assertEquals("刘亦菲", users.get(0).getName());
        Assert.assertTrue(users.get(0).getFlag());
    }
相关推荐
软件技术NINI几秒前
基于SpringBoot和Vue的项目评审系统
javascript·vue.js·spring boot·后端·spring·毕业设计·毕设
代码不停31 分钟前
Spring Aop
java·数据库·spring
Flynn Liang14 小时前
AI 应用的安全红线:Spring AI 下的 Prompt 注入防护、PII 脱敏、输出审计与密钥管理
人工智能·安全·spring·数据泄露·springai·prompt注入
QCoding14 小时前
企业级Agent Evaluation实战:Agent能跑就能上线?AI Agent到底怎么测?
后端·spring
code2cat15 小时前
Java工具篇之Gradle:用任务图组织构建与交付
java·开发语言·单元测试·gradle
Flynn Liang21 小时前
Spring AI 上生产:限流熔断、密钥与成本治理、私有化/混合部署、降级与 Prompt 灰度架构全解
人工智能·spring·架构·高可用·springai·成本治理·生产架构
Flynn Liang1 天前
Spring AI 2.0 深度解析:ChatClient、Advisor 链与 MCP——Java 工程师的 AI 落地最优解
java·人工智能·spring·大模型·架构设计·spring ai
liangbo71 天前
Spring系列01:IoC 与 DI 到底解决了什么
java·spring
杨凯凡1 天前
Spring Boot 的 @Transactional 为什么会失效?从代理、自调用到异常回滚的排查实战
java·spring boot·spring·事务·后端开发
哦虎!1 天前
【JavaEE进阶】SpringBoot
spring