如何用Mockito编写基于NamedParameterJdbcTemplate的DAO层JUnit测试用例
用Mockito编写DAO层测试用例(基于NamedParameterJdbcTemplate)
首先贴出原DAO层代码:
@Repository public class GeneratorRepository { @Value("${sql.existingUtQuery}") private String existingUtQuery; @Autowired private NamedParameterJdbcTemplate namedParameterJdbcTemplate; @Autowired private BeanPropertyRowMapper<Generator> generatorRowMapper; public Generator findExistingUt(Request request) { Generator ut = new Generator(); try { SqlParameterSource namedParameters = new MapSqlParameterSource() .addValue("no", request.getId(), Types.VARCHAR) .addValue("sub", request.getSub(), Types.VARCHAR) .addValue("rt", request.getRt(), Types.INTEGER) .addValue("sta", request.getSta(), Types.VARCHAR); ut = namedParameterJdbcTemplate.queryForObject(existingUtQuery, namedParameters, generatorRowMapper); } catch (EmptyResultDataAccessException e) { ut = null; } catch (Exception e) { throw e; } return ut; } }
你的测试用例存在几个问题:
- Mock方法参数错误:
when中第二个参数误传为namedParameterJdbcTemplate,实际应匹配SqlParameterSource类型参数 - 未注入DAO依赖的SQL语句:DAO中SQL从配置文件读取,测试时需手动设置该值
- 未覆盖全场景:仅测试正常返回情况,遗漏空结果、异常抛出场景
- Generator类未重写equals:直接用
assertEquals会因引用比对导致断言失败
完整测试用例
基础注解与依赖配置
使用Mockito注解管理Mock对象,通过反射注入DAO的SQL属性:
import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.junit.MockitoJUnitRunner; import org.springframework.jdbc.core.BeanPropertyRowMapper; import org.springframework.jdbc.core.namedparam.SqlParameterSource; import org.springframework.jdbc.EmptyResultDataAccessException; import static org.junit.Assert.*; import static org.mockito.Mockito.*; @RunWith(MockitoJUnitRunner.class) public class GeneratorRepositoryTest { @InjectMocks private GeneratorRepository generatorRepo; @Mock private NamedParameterJdbcTemplate namedParameterJdbcTemplate; @Mock private BeanPropertyRowMapper<Generator> generatorRowMapper; private final String TEST_SQL = "select Top 1 * from existingUT where NO= :no AND SUB= :sub AND rt= :rt and STA= :sta order by LAST_UPDATE desc"; public GeneratorRepositoryTest() { // 手动设置DAO中@Value注入的SQL属性 org.springframework.test.util.ReflectionTestUtils.setField(generatorRepo, "existingUtQuery", TEST_SQL); }
场景1:查询到数据,正常返回对象
@Test public void findExistingUt_WhenDataExists_ReturnsGenerator() { Request request = new Request("12345", "F", 0, "XC"); Generator expectedResponse = new Generator("12345", "F", 0, "XC","12345.FCST","345TDGHDF45G","OS01",null); // Mock queryForObject方法,匹配对应参数 when(namedParameterJdbcTemplate.queryForObject( eq(TEST_SQL), any(SqlParameterSource.class), eq(generatorRowMapper) )).thenReturn(expectedResponse); Generator actualResponse = generatorRepo.findExistingUt(request); // 断言结果并验证方法调用次数 assertEquals(expectedResponse, actualResponse); verify(namedParameterJdbcTemplate, times(1)).queryForObject( eq(TEST_SQL), any(SqlParameterSource.class), eq(generatorRowMapper) ); }
场景2:无查询结果,返回null
@Test public void findExistingUt_WhenNoData_ReturnsNull() { Request request = new Request("99999", "X", 1, "XX"); // Mock抛出空结果异常 when(namedParameterJdbcTemplate.queryForObject( eq(TEST_SQL), any(SqlParameterSource.class), eq(generatorRowMapper) )).thenThrow(new EmptyResultDataAccessException(1)); Generator actualResponse = generatorRepo.findExistingUt(request); assertNull(actualResponse); verify(namedParameterJdbcTemplate, times(1)).queryForObject( eq(TEST_SQL), any(SqlParameterSource.class), eq(generatorRowMapper) ); }
场景3:查询抛出异常,向上传递
@Test(expected = RuntimeException.class) public void findExistingUt_WhenExceptionThrown_ThrowsException() { Request request = new Request("11111", "Y", 2, "YY"); // Mock抛出运行时异常 when(namedParameterJdbcTemplate.queryForObject( eq(TEST_SQL), any(SqlParameterSource.class), eq(generatorRowMapper) )).thenThrow(new RuntimeException("数据库查询失败")); generatorRepo.findExistingUt(request); } }
关键注意事项
- @InjectMocks:自动将Mock对象注入到DAO实例中,无需手动初始化依赖
- 参数匹配:用
eq()匹配具体值,any()匹配任意类型参数,确保Mockito正确识别方法调用 - Generator类重写equals:必须重写
equals和hashCode方法,否则assertEquals会比对对象引用而非内容
内容的提问来源于stack exchange,提问作者Rahul
相关产品推荐
相关产品推荐

