2011-02-11 52 views
2

给定一个扩展SimpleJdbcDaoSupport的类,如何模拟SimpleJdbcTemplate?Spring JUnit和Mockito - 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没有影响。那么如何做到这一点,在没有公共setter的情况下,构建SimpleJdbcTemplate的唯一方法就是依赖该方法getSimpleJdbcObject()?

+0

无法使用你刚才ReflectionUtils它注入:http://static.springsource.org/spring/docs/3.0.x/api/org/springframework/util/ReflectionUtils.html? – esaj 2011-02-12 09:03:05

回答

0

你为什么要模拟JdbcTemplate?使用像HSQL这样的内存数据库的真实事物。

+0

我一直想知道,如果你使用HSQL而不是嘲笑,你会以某种方式做某种集成测试的单元测试,我说得对吗? – 2013-04-24 04:57:05

+1

@JuanAntonioGomezMoriano从纯粹主义者的角度来看,是的。我发现单元和集成测试之间的界限没有明确定义。我发现最有用的定义(尽管在语义上不是正确的)是:单元测试是任何不需要外部服务的东西,集成测试就是其他的东西。从这个角度来看,在内存数据库中可以进行单元测试。 – 2013-04-24 07:32:05

0

还有一件事。我通过将SimpleJdbcTemplate替换为JdbcTemplate来解决此问题。我对Java很陌生,从.Net世界转过来,最初只使用SimpleJdbcTemplate,这是因为我遇到了一些描述其用法的文档,它完全满足了我的需求。但Skaffman的意见让我更深入地调查了JdbcTemplate,然后我意识到我并不需要SimpleJdbcTemplate
尽管如此,问题的哲学部分仍然存在。你如何模拟只能通过询问容器本身创建的东西?在我看来,Spring在这里违反了DI原则,通过严格依赖容器。

3

而不是嘲笑具体的类,你应该嘲笑一个接口(它有你需要的方法)。

例如为:

public class SimpleJdbcDaoSupportExtension extends SimpleJdbcDaoSupport implements MyDomainDao{ 
    public SimpleJdbcDaoSupportExtension (JdbcTemplate jdbcTemplate){ 
      super.setJdbcTemplate(jdbcTemplate); 
    } 

    public MyDomainObj getResult(){ 
     SimpleJdbcTemplate sjdbc = getSimpleJdbcTemplate(); 
     MyDomainObj result = sjdbc.query(*whatever necessary args*.); 
     return result; 
    } 
} 

public class Test { 
    @Mock private MyDomainDao myDomainDao ; 
    private YourController yourController; 

    @Before 
    public void doBeforeEachTestCase() { 
     MockitoAnnotations.initMocks(this); 
     yourController = new YourController(myDomainDao); 
    } 
    @Test 
    public final void testSomething(){   
     when(myDomainDao.getResult().thenReturn(new MyDomainObj()); 
     //on to testing the usages of myDomainDao 
     yourController.doSomething(); 
     //verify 
     verify(myDomainDao, times(2)).getResult(); 
    } 
} 
0

的另一种方法,使您可以测试更多的DAO是嘲笑连接的PreparedStatement和ResultSet。这不仅仅是模拟jdbctemplate,还有一点工作要做,但是可以让您验证预处理语句是否设置了正确的值,以及您的自定义行映射器是否正常工作。

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()); 
} 
}