The need for refactoring to improve testing

I am testing a simple DAO layer with mockito, but I found the problem, basically a tough interface to test, and I was wondering if you can give me some idea ...

This is the method I want to check:

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;
  }

I use DatabaseGateway, which is my interface between Java code and SQL, and this method accepts an anonymous class, this is the executeQuery method 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);
    }
  }

The fact is that because of this anonymous class, it becomes harder for him to test PersonDAO.

I can reorganize all the code, even delete an anonymous class, if someone offers a better design (I'm sure there is simpler, but I just can not find it).

Thanks everyone for the suggestions.

PD: if you need more 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 , ... ?

+1
2

. executeQuery .

, . ( ), .

:

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);
    }
  }
+1

"" arg ResultSetCommand, mock ResultSet:

/**
 * Custom matcher - always returns true, but captures the
 * ResultSetCommand param
 */
class CaptureArg extends ArgumentMatcher<ResultSetCommand> {
    ResultSetCommand resultSetCommand;
    public boolean matches(Object resultSetCommand) {
         resultSetCommand = resultSetCommand;
         return true;
    }
}

public void testGetPersonById(){
    // setup expectations...
    final String lastName = "Smith";
    final String firstName = "John";
    final CaptureArg captureArg = new CaptureArg();
    DatabaseGateway gateway = mock(DatabaseGateway.class);
    ResultSet mockResultSet = mock(ResultSet.class);
    when(gateway.executeQuery(anyString(), argThat(captureArg) ));
    when(mockResultSet.next()).thenReturn(Boolean.True);
    when(mockResultSet.getString("name")).thenReturn(firstName);
    when(mockResultSet.getString("last_name")).thenReturn(lastName);

    // run the test...
    PersonDAO person_dao = new PersonDAOImpl(gateway);
    Person p = person_dao.getById(new UserId(Type.viewer,"100"));

    // simulate the callback...
    captureArg.resultSetCommand.work(mockResultSet);

    // verify
    assertEquals(firstName, person.getName().getGivenName());
    assertEquals(lastName, person.getName().getFamilyName());
}

, - , . , , .

0

Source: https://habr.com/ru/post/1712907/


All Articles