Java Spring JUnit和Mockito-SimpleJdbcTemplate
给定一个扩展SimpleJdbcDaoSupport的类,如何模拟SimpleJdbcTemplateJava Spring JUnit和Mockito-SimpleJdbcTemplate,java,spring,mockito,jdbctemplate,Java,Spring,Mockito,Jdbctemplate,给定一个扩展SimpleJdbcDaoSupport的类,如何模拟SimpleJdbcTemplate public class SimpleJdbcDaoSupportExtension extends SimpleJdbcDaoSupport { public SimpleJdbcDaoSupportExtension (JdbcTemplate jdbcTemplate){ super.setJdbcTemplate(jdbcTemplate);
public class SimpleJdbcDaoSupportExtension extends SimpleJdbcDaoSupport {
public SimpleJdbcDaoSupportExtension (JdbcTemplate jdbcTemplate){
super.setJdbcTemplate(jdbcTemplate);
}
public MyDomainObj getResult(){
SimpleJdbcTemplate sjdbc = getSimpleJdbcTemplate();
MyDomainObj result = sjdbc.query(*whatever necessary args*.);
return result;
}
}
然后,使用Mockito:
public class Test {
@Mock private JdbcTemplate mockedJdbcTemplateDedendency;
private SimpleJdbcDaoSupportExtension testObj;
@Before
public void doBeforeEachTestCase() {
MockitoAnnotations.initMocks(this);
SimpleJdbcDaoSupportExtension sje = new SimpleJdbcDaoSupportExtension (mockedJdbcTemplateDedendency);
}
@Test
public final void test(){
when(mockedJdbcTemplateDedendency.query("what to query").thenReturn(new MyDomainObj());
}
}
模拟JdbcTemplate被注入,但由于dao类依赖SimpleJdbcTemplate进行查询(用于映射到对象),并且它是由SimpleJdbcDaoSupport在内部构建的,因此模拟JdbcTemplate对SimpleJdbcTemplate没有影响。那么,在没有公共setter的情况下,如何做到这一点,并且构造SimpleJdbcTemplate的唯一方法是依赖该方法getSimpleJdbcObject()?为什么要模拟JdbcTemplate?将真实的东西与内存中的数据库(如HSQL)结合使用。还有一件事。我通过用JdbcTemplate替换SimpleJDBCCTTemplate解决了这个问题。我对Java有点陌生,从.Net世界过渡过来,最初使用SimpleJdbcTemplate只是因为我遇到了一些描述其用法的文档,这些文档完美地满足了我的需求。但是Skaffman的评论让我更深入地研究了JdbcTemplate,然后我意识到我并不真正需要SimpleJdbcTemplate。
尽管如此,问题的哲学部分仍然存在。如何模拟只能通过询问容器本身来创建的东西?在我看来,Spring在这里违反了DI原则,它严格依赖于容器 不应该模拟具体类,而应该模拟接口(它具有所需的方法) e、 g:
允许您测试更多dao的另一种方法是模拟连接、preparedstatement和resultset。这比模拟jdbctemplate要多做一点工作,但将允许您验证preparedstatement是否设置了正确的值,以及自定义行映射器是否正常工作
public class Test {
private MyDao dao;
private JdbcTemplate jdbcTemplate;
private Connection conn;
private PreparedStatement ps;
private ResultSet rs;
@Before
public void setUp() throws Exception {
dao = new MyDao();
conn = mock(Connection.class);
ps = mock(PreparedStatement.class);
rs = mock(ResultSet.class);
jdbcTemplate = new JdbcTemplate(new SingleConnectionDataSource(conn, false));
doa.setJdbcTemplate(jdbcTemplate);
}
@Test
public void test() throws Exception {
when(conn.prepareStatement(any(String.class))).thenReturn(ps);
when(ps.executeQuery()).thenReturn(rs);
// return one row
when(rs.next()).thenReturn(true).thenReturn(false);
when(rs.getInt("id")).thenReturn(1234);
when(rs.getString("name")).thenReturn("Bob");
MyDto myDto = dao.someDaoMethod(...)
// verify ParameterSource
verify(ps, times(1)).setInt(1, 1234);
// these verify if you are mapping the columns to the right object attribute.
assertEquals(1234, myDto.getId().intValue());
assertEquals("Bob", myDto.getName());
}
}
难道你不能用ReflectionUtils注入它吗?“我一直在想,如果你用HSQL而不是嘲笑你,你就不会通过某种集成测试进行真正的单元测试,对吗?”胡安南托尼奥戈梅佐里亚诺(Juanantonigomezmoriano)从纯粹主义者的角度看,是的。我发现单元测试和集成测试之间的边界没有明确定义。我发现最有用的定义(虽然在语义上不正确)是:单元测试是不需要外部服务的任何东西,而集成测试是其他一切。从这个角度来看,内存中的DBs可以进行单元测试。感谢您的解释:)@SeanPatrickFloyd如果我的代码使用了50多个表,每个表中有200多个列,那该怎么办。您在单元测试中创建了整个db模式??我不明白这一点。对你的问题的准确答案是,你需要使用一个模拟库,它支持从给定的基类型模拟未指定的实现类。JMockit(我开发的模拟工具)通过
@Capturing
注释提供上述支持,用于声明模拟字段/参数。
public class Test {
private MyDao dao;
private JdbcTemplate jdbcTemplate;
private Connection conn;
private PreparedStatement ps;
private ResultSet rs;
@Before
public void setUp() throws Exception {
dao = new MyDao();
conn = mock(Connection.class);
ps = mock(PreparedStatement.class);
rs = mock(ResultSet.class);
jdbcTemplate = new JdbcTemplate(new SingleConnectionDataSource(conn, false));
doa.setJdbcTemplate(jdbcTemplate);
}
@Test
public void test() throws Exception {
when(conn.prepareStatement(any(String.class))).thenReturn(ps);
when(ps.executeQuery()).thenReturn(rs);
// return one row
when(rs.next()).thenReturn(true).thenReturn(false);
when(rs.getInt("id")).thenReturn(1234);
when(rs.getString("name")).thenReturn("Bob");
MyDto myDto = dao.someDaoMethod(...)
// verify ParameterSource
verify(ps, times(1)).setInt(1, 1234);
// these verify if you are mapping the columns to the right object attribute.
assertEquals(1234, myDto.getId().intValue());
assertEquals("Bob", myDto.getName());
}
}