Spring JUnit 和 Mockito - SimpleJdbcTemplate
给定一个扩展 SimpleJdbcDaoSupport 的类,如何模拟 SimpleJdbcTemplate?
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内部构造的 - 模拟JdcbTemplate对SimpleJdbcTemplate没有影响。那么,当没有公共设置器时,并且信任 SimpleJdbcTemplate 的唯一方法是依赖该方法 getSimpleJdbcObject() 时,该如何做到这一点?
Given a class that extends SimpleJdbcDaoSupport, how can you mock SimpleJdbcTemplate?
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;
}
}
Then, using 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());
}
}
The mocked JdbcTemplate is injected, but since the dao class relies on SimpleJdbcTemplate to make queries (for mapping to objects), and it's constructed internally by SimpleJdbcDaoSupport - mocking JdcbTemplate has no effect on the SimpleJdbcTemplate. So how to do this, when there are no public setters for it, and the only way to construst SimpleJdbcTemplate is to rely on that method, getSimpleJdbcObject()?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
您应该模拟一个接口(它具有您需要的方法),而不是模拟具体的类。
例如:
Instead of mocking the concrete class, you ought to be mocking an interface (which has the methods you need).
e.g.:
为什么要嘲笑 JdbcTemplate?使用 HSQL 等内存数据库来进行实际操作。
Why would you mock JdbcTemplate? Use the real thing with an in-memory database like HSQL.
还有一件事。我通过将 SimpleJdbcTemplate 替换为 JdbcTemplate 解决了这个问题。我对 Java 有点陌生,从 .Net 世界跨界而来,最初使用 SimpleJdbcTemplate 只是因为我遇到了一些描述其用法的文档,这些文档完美地满足了我的需求。但 Skaffman 的评论让我更深入地研究了JdbcTemplate,然后我意识到我并不真正需要SimpleJdbcTemplate。
尽管如此,问题的哲学部分仍然存在。如何模拟只能通过询问容器本身来创建的东西?在我看来,Spring 对容器的紧密依赖违反了 DI 原则。
And one more thing. I resolved this issue by replacing SimpleJdbcTemplate with JdbcTemplate. I am kind of new to Java, crossing over from the .Net world, and originally went with SimpleJdbcTemplate only because I came across some documentation describing its usage which perfectly answered my needs. But Skaffman's comments led me to investigate JdbcTemplate more deeply, and then I realized I didn't really need SimpleJdbcTemplate.
Nevertheless, the philosophical part of the question still stands. How do you mock something that can only be created by asking the container itself? Seems to me that Spring is violating the DI principle here, by making a tight dependency on the container.
另一种允许您测试更多 dao 的方法是模拟连接、准备好的语句和结果集。这比仅仅模拟 jdbctemplate 需要做更多的工作,但它允许您验证准备好的语句是否设置了正确的值,以及您的自定义行映射器是否正常工作。
Another way that allows you to test more of the dao is to mock the connection, preparedstatement, and resultset. It's a little more work than just mocking the jdbctemplate, but will allow you to verify if the preparedstatement is setting the correct value, and if your custom row mapper is working correctly.