2011-02-11 54 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()); 
} 
}