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());
    }
相关推荐
慧都小项33 分钟前
Parasoft C/C++test如何使用桩函数替代MFC窗口类顺利执行单元测试
单元测试·parasoft·桩函数·mfc窗口类
YDS8291 小时前
苍穹外卖 —— Spring Cache和购物车功能开发
java·spring boot·后端·spring·mybatis
Elieal1 小时前
Spring 框架核心技术全解析
java·spring·sqlserver
组合缺一1 小时前
(对标 Spring)OpenSolon v3.7.0, v3.6.4, v3.5.8, v3.4.8 发布(支持 LTS)
java·后端·spring·web·solon
♡喜欢做梦2 小时前
Spring IOC
java·后端·spring
慧都小项10 小时前
Parasoft C/C++test中Trace32调试器的配置与单元测试执行
单元测试·parasoft·trace32调试器
葡萄城技术团队11 小时前
迎接下一代 React 框架:Next.js 16 核心能力解读
javascript·spring·react.js
灰小猿12 小时前
Spring前后端分离项目时间格式转换问题全局配置解决
java·前端·后端·spring·spring cloud
知其然亦知其所以然18 小时前
这波AI太原生了!SpringAI让PostgreSQL秒变智能数据库!
后端·spring·postgresql
zhaomx198921 小时前
Spring 事务管理 Transaction rolled back because it has been marked as rollback-only
数据库·spring