2

给定一个扩展 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()?

4

4 回答 4

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();
    }
}
于 2011-02-15T09:26:16.180 回答
0

为什么要模拟 JdbcTemplate?将真实的东西与 HSQL 等内存数据库一起使用。

于 2011-02-12T10:47:25.447 回答
0

允许您测试更多 dao 的另一种方法是模拟连接、preparedstatement 和结果集。这比仅仅模拟 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());
}
}
于 2015-01-08T15:24:36.277 回答
0

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

于 2011-02-13T06:03:02.250 回答