【问题标题】:Mocking getJdbcTemplate method模拟 getJdbcTemplate 方法
【发布时间】:2014-10-15 12:42:12
【问题描述】:

我的场景如下:

我在SampleDao界面中有no setter methods,在SampleDaoImpl类中有no direct field

参考:How to mock getJdbcTemplate().queryForObject()?

public interface SampleDao {
    // some methods
}

public class SampleDaoImpl extends JdbcDaoSupport implements SampleDao {
    // implementation of some methods
    public String someMethod(String param1, String param2){
        // .....//
        List<String> data = getJdbcTemplate().query(.....);  // -> getJdbcTemplate() is the method of JdbcDaoSupport to get JdbcTemplate
    }
}

我想模拟getJdbcTemplate().query(.....) 的结果,其中getJdbcTemplate() 属于JdbcDaoSupport 类,由SampleDaoImpl 扩展,SampleDao 没有。

我的测试用例如下:

创建SampleDaoImpl的对象并分配给SampleDao

@RunWith(Parameterized.class)
public class MockSampleDao {

    String param1 = "", param2 = "";
    @Mock
    SampleDao sampleDao = new SampleDaoImpl();


    public MockSampleDao(String param1, String param2) {
        super();
        this.param1 = param1;
        this.param2 = param2;   
    }

    @Parameterized.Parameters
    public static Collection primeNumbers() {
        return Arrays.asList(new Object[][] { 
            { "test1", "test1" },
            { "test2", "test2" }
        });
    }

    @Test
    public void testSomeMethod(){
        try {
        // HOW TO MOCK THE RESULT FROM getJdbcTemplate().query() HERE

            sampleDao.someMethod(param1, param2);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

}

【问题讨论】:

  • JdbcDaoSupport 从哪里获取它从 getJdbcTemplate() 返回的值?也许您可以模拟用于生成该 jdbcTemplate 的对象?

标签: java mockito junit4


【解决方案1】:

你在嘲笑错误的对象。您正在尝试测试 SampleDaoImpl.someMethod(),因此您必须创建一个 具体 SampleDaoImpl 实例,而不是模拟实例。

一旦你有了一个具体的实例,你就可以调用setJdbcTemplate() 并传入一个mocked JdbcTemplate 对象。最后,您可以控制该模拟的行为,以便当someMethod() 调用query() 时,返回您的首选数据。

例如:

public class MockSampleDao {

    // parameterized stuff omitted for brevity

    @Test
    public void testSomeMethod() throws Exception {

      SampleDaoImpl impl = new SampleDaoImpl();
      JdbcTemplate template = mock(JdbcTemplate.class);
      List<String> someList = // populate this list
      when(template.query(....)).thenReturn(someList);

      impl.setJdbcTemplate(template);
      impl.someMethod(param1, param2);

      // further testing etc.
    }

}

【讨论】:

  • (+1) 作为一种变通方法,我喜欢下面的方法,类似于你所说的。但张贴更好的方法。 @Mock SampleDaoImpl sampleDao = new SampleDaoImpl();
  • @NamingException 我不明白那个评论。你根本不应该嘲笑SampleDaoImpl
  • 抱歉,已编辑评论。通过为 SampleDaoImple 创建对象,我可以直接模拟 getJdbcTemplate(),因为它扩展了 JdbcDaoSupport 类
  • @NamingException 我想这种方法也可以。但我总是希望尽可能避免嘲笑我的测试类 - 乍一看令人困惑。在这种情况下,这是完全可以避免的,这要归功于方便的 setJdbcTemplate() 方法。
【解决方案2】:

应该是这个样子(根据你要覆盖的JdbcTemplate的查询API来调整mock):

@RunWith(Parameterized.class)
public class MockSampleDao extends SampleDaoImpl{
      JdbcTemplate jdbcTemplate = mock(JdbcTemplate.class);

     @Override
     protected JdbcTemplate getJdbcTemplate(){
        return jdbcTemplate;
     }

    @Test
    public void testSomeMethod(){
        try {
             when(jdbcTemplate.query(/* put here the api that you want to overload*/)).
             thenReturn(/* the mock output that you want */);

            sampleDao.someMethod(param1, param2);
        } catch (Exception e) {
            e.printStackTrace();
        }
}

【讨论】:

  • sampleDao.getJdbcTemplate() 是不可能的,正如我一开始提到的。 getJdbcTemplate() 与接口 SampleDao 没有任何关系...作为一种解决方法,我已经对 @Duncan 提到的模拟 SampleDaoImpl 做过。但正在寻找更好的方法。
  • @NamingException 可以尝试其他方法 - 从 SampleDaoImpl 扩展并覆盖 getJdbcTemplate 方法。那是因为你的班级有超过 1 个“角色” - 它是 JdbcDaoSupportSampleDao - 如果你在界面中添加方法 getDao 将解决你的问题
  • -1:扩展测试类不是正确的方法。
  • @Duncan 我认为在某些情况下这样做是正确的。我更新了上面的评论——在这种情况下,SampleDao 不授予对 doa 的访问权限——我认为这是要走的路。更新接口将消除扩展测试类的需要。同样在单元测试中你想测试protected 方法
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-02-18
  • 2017-09-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多