为什么Mockito在数据访问调用中不使用我的模拟?[duplicate]

anhgbhbe  于 2022-11-08  发布在  其他
关注(0)|答案(1)|浏览(134)

此问题在此处已有答案

Why is my class not calling my mocked methods in unit test?(1个答案)
23天前关闭。
我声称我的测试失败是因为我的被测试类没有看到mock。我的证据是:

  • 在调试器中,我的对象有普通的java.sql.* 父对象,它们不是Mockito.* 的。
  • 当我尝试单步执行DbSql之类的对象时,我看到的是实际的DbSql代码,而不是Mockito代码。
  • 当我运行时,executeQuery()抛出了一个NullPointerException。

以下是我的测试类的部分内容:

//  Test Class
//  My mocks:
HostMessage mockHostMessage;
DbConnect mockDbConnect;
DbCache mockDbCache;
DbSql mockDbSql;
ResultSet mockResultSet;

@BeforeEach
void setUp()
{
  mockHostMessage     = Mockito.mock(HostMessage.class);
  mockDbConnect       = Mockito.mock(DbConnect.class);
  mockDbCache         = Mockito.mock(DbCache.class);
  mockDbSql           = Mockito.mock(DbSql.class);
  mockResultSet       = Mockito.mock(ResultSet.class);
}

@Test
void myTest() {
  String errMsg = "something";

  try {
    doReturn(mockDbSql).when(mockDbCache).getDbSql(any(), anyString());
    doReturn(mockResultSet).when(mockDbSql).executeQuery();
    doReturn(false).when(mockResultSet).next();
    (new CartonRoutingProcessor()).process(mockDbConnect, mockHostMessage);
  } catch(Throwable t) {

    if(t instanceof MockitoException) {
      fail(t.getMessage());
    } else if(t instanceof SqlException) {
      Assertions.assertTrue(t.getMessage().contains(errMsg),
           "Phrase not found in SqlException message: " + errMsg);
      fail(t.getMessage());
    } else {
      fail(t.getMessage());
    }

  }

下面是我的CartonRoutingProcessor业务逻辑的一部分:

public boolean process(DbConnect conn, HostMessage msg) throws SQLException
{
  try(DbCache dbc = new DbCache())
  {
    DbSql mySql = dbc.getDbSql(conn, String.format("select id from routes"));

    // Throws NullPointerException right here, 
    // while trying to execute the query rather than mock it.
    ResultSet rs = mySql.executeQuery();

    String routeType = rs.next() ? rs.getString("id") : null;
    ...
  }
  ...
}

Mockito手册和大量的网页都讲述了如何执行此任务。
然而我没有得到我应该得到的结果。
一个善良的开发者能给我一个提示吗?

fnx2tebb

fnx2tebb1#

这里您使用的是真实的实现而不是模拟

try(DbCache dbc = new DbCache())
  {
   ///dbc is a real instance of DbCache()
    DbSql mySql = dbc.getDbSql(conn, String.format("select id from routes"));

因此,在特定的测试场景中,您的模拟不会被使用。
当我看到一个mock返回一个mock返回一个mock时(等等,你明白了),我开始觉得要么代码是不可测试的,要么我的测试方法是糟糕的。毕竟,你想在这里测试什么?
假设您希望验证调用层响应process方法的true/false结果的行为。在这种情况下,可以模拟/监视整个process,并人工创建响应,以便您可以专注于特定功能-响应结果
另一方面,您可能希望测试process方法实际上是如何工作的,以及是否正确地获取了路由类型-但您应该使用actualtDB(例如,可以在内存中,如H2)来验证您是否正确地与DB交互,或者您可以在另一个将被监视的方法中进行整个获取。
正确的方法取决于测试的实际目标及其范围(单元测试的范围非常窄-测试例如单一方法)。
在您的情况下,由于不是所有的“片段”都可以从外部提供(在这种情况下是模拟),我将坚持使用内存中的数据库-要做的存根较少。缺点是,现在您必须在数据库中准备实际数据,以便设置场景,这可能会很麻烦。

相关问题