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());
    }
相关推荐
小江的记录本1 天前
【Spring全家桶】Spring Cloud 2023.0.x:微服务核心理论、CAP/BASE定理(附《思维导图》+《面试高频考点清单》)
java·spring boot·后端·spring·spring cloud·微服务·面试
Solis程序员1 天前
缓存三剑客预防策略
java·spring·缓存
我登哥MVP1 天前
Spring Boot 从“会用”到“精通”:Model-Map原理
java·spring boot·后端·spring·servlet·maven·mybatis
phltxy1 天前
Spring AI Alibaba 多模态应用开发实践
java·人工智能·spring
折哥的程序人生 · 物流技术专研1 天前
【电商多平台电子面单对接实战|第二篇】抖音代发电子面单对接:从“面条代码”到整洁架构的涅槃之路
设计模式·架构·系统架构·单元测试·代码规范·单一职责原则
闪电悠米1 天前
黑马点评-秒杀优化-04_lua_and_db_fallback
服务器·开发语言·网络·数据库·缓存·junit·lua
西凉的悲伤1 天前
Spring Security + JWT 登录认证完整实践指南
java·后端·spring·spring security·jwt
无忧.芙桃1 天前
vibe coding之opencode的使用
ai·单元测试·opencode
闪电悠米1 天前
黑马点评-秒杀优化-03_blocking_queue_async_order
数据库·分布式·oracle·junit·wpf·lua
MageGojo2 天前
天气 API 接入实战:基于 ApiZero 实现实时天气、分钟级降水和 15 天预报查询
java·后端·spring·api 接口接入·接口实战