Java Spring JUnit和Mockito-SimpleJdbcTemplate

Java 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);

给定一个扩展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在内部构建的,因此模拟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());
}
}