需要重构以提高可测性 [英] In Need of Refactoring in Order to Improve Testability

查看:141
本文介绍了需要重构以提高可测性的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用mockito测试一个简单的DAO层,但我发现了一个问题,基本上是一个难以测试的界面,我想知道你是否可以给我一些见解......

I'm testing a simple DAO layer with mockito but I found a problem, basically a hard to test interface and I was wondering if you could give me some insight...

这是我想测试的方法:

public Person getById(UserId id) {
    final Person person = new PersonImpl();

    gateway.executeQuery(GET_SQL + id.getUserId(), new ResultSetCommand(){
      public int work(ResultSet rs) throws SQLException {
        if(rs.next()){
          person.getName().setGivenName(rs.getString("name"));
          person.getName().setFamilyName(rs.getString("last_name"));
        }
        return 0;
      }
    });
    return person;
  }

我使用的是DatabaseGateway,这是我在java代码和SQL之间的接口,方法接受一个匿名类,这是网关的executeQuery方法:

I use a DatabaseGateway that is my interface between java code and SQL, and that method accepts an anonymous class, this is the method executeQuery of the gateway:

 public int executeQuery(String sql, ResultSetCommand cmd) {
    try{
      Connection cn =  createConnection();
      PreparedStatement st = cn.prepareStatement(sql);
      int result = cmd.work(st.executeQuery());
      cn.close();
      return result;
    }catch(Exception e){
      throw new RuntimeException("Cannot Create Statement for sql " + sql,e);
    }
  }

事情是,因为那个匿名类,测试PersonDAO变得越来越难。

The thing is that, because of that anonymous class, It's getting harder to test PersonDAO.

我可以重构整个代码,如果有人建议更好的设计,甚至删除匿名类(我确信有一个更简单的,但我似乎无法找到它。)

I can refactor the whole code, even remove the anonymous class if someone suggest a better design (I'm sure there's a simpler one, but I just can't seem to find it).

感谢大家的建议。

PD:如果您需要更多信息,请随时询问

PD: if you need further information, feel free to ask

编辑:测试很难

public void testGetPersonById(){
    DatabaseGateway gateway = mock(DatabaseGateway.class);
    when(gateway.executeQuery(anyString(),any(ResultSetCommand.class)));
    PersonDAO person_dao = new PersonDAOImpl(gateway);

    Person p = person_dao.getById(new UserId(Type.viewer,"100"));
  }

看? ResultCommand是模拟的一部分,我也对测试该代码感兴趣...我应该对该特定命令进行单独的测试吗?

See? ResultCommand is part of the mock, and I'm interested in testing that code too... should I do a separate test for that specific command?

推荐答案

您可以单独创建一个接口及其实现,而不是使用匿名类。然后executeQuery方法会有一个String和这个接口作为参数。

Instead of using anonymous classes, you could create an interface and its implementation separately. The method executeQuery would then have a String and this interface as a parameter.

所以你的测试将保持不变。您可以在另一个测试(接口实现的测试)中分离工作方法,这看起来很难测试。

So your test would remain the same. You would be able to separate the work method in another test (the test for your interface implementation), which looks like is the hard thing to test.

结果将是类似于:

public Person getById(UserId id) {
    final Person person = new PersonImpl();

    gateway.executeQuery(GET_SQL + id.getUserId(), new MyInterfaceImpl(person));
    return person;
}

public int executeQuery(String sql, MyInterface cmd) {
    try{
      Connection cn =  createConnection();
      PreparedStatement st = cn.prepareStatement(sql);
      int result = cmd.work(st.executeQuery());
      cn.close();
      return result;
    }catch(Exception e){
      throw new RuntimeException("Cannot Create Statement for sql " + sql,e);
    }
  }

这篇关于需要重构以提高可测性的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆