Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/320.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 如何在mockito中使用ArgumentCaptor_Java_Mockito - Fatal编程技术网

Java 如何在mockito中使用ArgumentCaptor

Java 如何在mockito中使用ArgumentCaptor,java,mockito,Java,Mockito,我正在学习Mockito和单元测试。我想学习如何使用参数捕获器更好地进行单元测试。我正在使用jdbc处理我的SQL语句。我有一个将用户插入数据库的方法 public void insert(User user) { String sql = "INSERT INTO user (id) VALUES ?"; jdbcTemplate.update(new PreparedStatementCreator() { @Override public PreparedS

我正在学习Mockito和单元测试。我想学习如何使用参数捕获器更好地进行单元测试。我正在使用jdbc处理我的SQL语句。我有一个将用户插入数据库的方法

public void insert(User user) {
   String sql = "INSERT INTO user (id) VALUES ?";
   jdbcTemplate.update(new PreparedStatementCreator() {
     @Override
     public PreparedStatement createPreparedStatement(Connection connection) {
       final PreparedStatement ps = connection.prepareStatement(sql);
       ps.setString(1, user.getId().trim());
       return ps;
     }
   });
 }
下面是我试图用ArgumentCaptor编写的测试

    @Test
      public void testInsert() {
        User user = new User("testID");
        ArgumentCaptor<PreparedStatementCreator> captor = ArgumentCaptor.forClass(PreparedStatementCreator.class);
        insert(user);
        verify(mockJdbc, times(1)).update(captor.capture());
        PreparedStatementCreator actual = captor.getValue();
        assertEquals(??, actual.createPreparedStatement(??));
      }
@测试
公共无效测试集(){
用户=新用户(“testID”);
ArgumentCaptor=ArgumentCaptor.forClass(PreparedStatementCreator.class);
插入(用户);
验证(mockJdbc,times(1)).update(captor.capture());
PreparedStatementCreator-actual=captor.getValue();
资产质量(?),实际的.createPreparedStatement(?);
}
关于assert语句的“??”中应该包含什么内容,或者这是否是使用参数Captor的正确方法,有什么建议或见解吗

多谢各位

编辑:

@测试
public void testInsert()引发SQLException{
ArgumentCaptor=ArgumentCaptor.forClass(PreparedStatementCreator.class);
PreparedStatement ps=mockConnection.prepareStatement(“插入用户(id)值?”;);
ps.setString(1,user.getId().trim());
插入(用户);
验证(mockJdbcTemplate,times(1)).update(captor.capture());
PreparedStatementCreator-actual=captor.getValue();
assertEquals(ps,actual.createPreparedStatement(mockConnection));
}

我喜欢你使用
ArgumentCaptor的方法

您正在正确使用
ArgumentCaptor
捕获模拟JDBC模板上方法
update
的参数;但是,您无法提取用于调用
PreparedStatementCreator
的参数,因为该对象不是模拟对象

从概念上讲,测试这部分代码的困难在于您无法控制
PreparedStatementCreator
的创建。一个可能的解决方案是重新控制创建这些对象的方式和时间;这样你就可以在测试中模仿他们了

按照标准,您可以引入一个工厂,该工厂(单一)的职责是创建
PreparedStatementCreator

interface PreparedStatementCreatorFactory {

  PreparedStatementCreator newPreparedStatementCreator(Connection connection, String sql, User user);

}

public final class DefaultPreparedStatementCreatorFactory {
  @Override
  public PreparedStatementCreator newPreparedStatementCreator(Connection connection, String sql, User user) {
    final PreparedStatement ps = connection.prepareStatement(sql);
    ps.setString(1, user.getId().trim());
    return ps;
  }
}
然后,在您正在测试的类(包含JDBC模拟)中,您可以插入
PreparedStatementCreatorFactory的模拟。然后,您可以在工厂中捕获参数,而不是捕获JDBC模拟的参数;当然,还要指定模拟工厂返回的内容

PreparedStatementCreatorFactory factory = Mockito.mock(PreparedStatementCreatorFactory.class);
PreparedStatementCreator creator = Mockito.mock(PreparedStatementCreator.class);
// Mock the creator at your convenience.

when(factory.newPreparedStatementCreator(any(Connection.class), any(String.class), any(User.class)).thenReturn(creator);

...

User user = new User("testID");
ArgumentCaptor<Connection> connectionCaptor = ArgumentCaptor.forClass(Connector.class);
ArgumentCaptor<String> sqlCaptor = ArgumentCaptor.forClass(String.class);
ArgumentCaptor<User> userCaptor = ArgumentCaptor.forClass(User.class);

insert(user);

verify(factory, times(1)).newPreparedStatementCreator(connectionCaptor.capture(), sqlCaptor.capture(), userCaptor.capture());

assertEquals(user, userCaptor.getValue());
PreparedStatementCreatorFactory=Mockito.mock(PreparedStatementCreatorFactory.class);
PreparedStatementCreator=Mockito.mock(PreparedStatementCreator.class);
//在你方便的时候嘲笑造物主。
当(factory.newPreparedStatementCreator(any(Connection.class)、any(String.class)、any(User.class))。然后返回(creator);
...
用户=新用户(“testID”);
ArgumentCaptor connectionCaptor=ArgumentCaptor.forClass(Connector.class);
ArgumentCaptor sqlCaptor=ArgumentCaptor.forClass(String.class);
ArgumentCaptor userCaptor=ArgumentCaptor.forClass(User.class);
插入(用户);
验证(工厂,时间(1)).newPreparedStatementCreator(connectionCaptor.capture(),sqlCaptor.capture(),userCaptor.capture());
assertEquals(user,userCaptor.getValue());

这种方法的一个缺点是增加了一级间接性和相对复杂性;正如我们所看到的,主要优点是改进了设计中关注点的分离,并提高了代码的可测试性。

感谢您的输入,我想使用ArgumentCaptor的主要原因是要确保PreparedStatement是b正在使用正确的值调用,即user.getId()。您的方法还会用于此吗?@Rp5595是的,您应该能够使用
userCaptor
验证用户的值。我在我的原始帖子中添加了一个编辑。是否可以从调用中捕获PreparedStatement并将其与我在本地创建的PreparedStatement进行比较?@Rp5595:不,很遗憾,这赢了“无法工作,因为
PreparedStatementCreator actual
不是模拟对象,即使它被参数captor捕获。这是因为您正在测试的代码创建了此对象,这阻止了您对其进行模拟,这就是为什么我在设计中引入了此附加工厂。它可能会增加一些复杂性,但这为您提供了一个很小的解决方案。”r负责创建
PreparedStatementCreator
的单一责任类。如果您想共享您正在测试的实际类,我可以添加我想到的关于如何将工厂注入其中的代码。您是否有我可以通过电子邮件与您进行沟通的电子邮件?
PreparedStatementCreatorFactory factory = Mockito.mock(PreparedStatementCreatorFactory.class);
PreparedStatementCreator creator = Mockito.mock(PreparedStatementCreator.class);
// Mock the creator at your convenience.

when(factory.newPreparedStatementCreator(any(Connection.class), any(String.class), any(User.class)).thenReturn(creator);

...

User user = new User("testID");
ArgumentCaptor<Connection> connectionCaptor = ArgumentCaptor.forClass(Connector.class);
ArgumentCaptor<String> sqlCaptor = ArgumentCaptor.forClass(String.class);
ArgumentCaptor<User> userCaptor = ArgumentCaptor.forClass(User.class);

insert(user);

verify(factory, times(1)).newPreparedStatementCreator(connectionCaptor.capture(), sqlCaptor.capture(), userCaptor.capture());

assertEquals(user, userCaptor.getValue());