mockito 单元测试:正在使用for循环处理集合,而不是使用流处理集合

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

单元测试的问题是同一个集合在流和for循环中的处理方式不同。两种情况下的集合都是空的(data.size() = 0),但在第一种情况下,该集合以某种方式进行了处理,换句话说,它将进入for循环。在第二种情况下,该集合被跳过(这是意料之中的,因为它是空的)。
测试使用Mockito,Result<Record>将用于JOOQ。
测试是旧的,没有变化,唯一的变化是从for循环到流。

案例1

private SearchResult iterateData(
      Result<Record> data, ...) {

      for (Record record : data) {
           doSomething(record);
    }

案例2

private SearchResult iterateData(
      Result<Record> data, ...) {
      data.stream().forEach(record -> doSomething(record));

案例1 for loop example截图

模拟的结果对象

private DefaultSearchRequestModel rowSpecificValuesTestSetup(
      parameters...) {

    DefaultSearchRequestModel searchRequest = new DefaultSearchRequestModel(
        Arrays.asList(....),
        Collections.singletonList(
            new SearchFilter(
                "test",
                Collections.singletonList(...)));

    List<Column> columns =
        this.searchService.filterUserAllowedColumns(...);

    Condition searchCondition =
        this.searchRepositoryMock.getSearchConditions(...);

    List<TableJoinMapping> joinMappings = ColumnHelper.getColumnTranslateDeviceJoinMappings(
        columns,
        searchRequest.getFilters());

    Result<Record> deviceDataResultMock = Mockito.mock(Result.class);
    Iterator<Record> resultIterator = Mockito.mock(Iterator.class);
    final Table fromTableMock = Mockito.mock(Table.class);
    when(resultIterator.hasNext()).thenReturn(true, false);
    Record recordMock = Mockito.mock(Record.class);
    when(resultIterator.next()).thenReturn(recordMock);
    when(deviceDataResultMock.iterator()).thenReturn(resultIterator);
    when(recordMock.get(CONTRACTID)).thenReturn(contractId);
   ...
when(this.userPermissions.getAccessPermissions()).thenReturn(searchRequest.getColumns().stream().map
        (name -> Column.findByName(name).getId()).collect(
        Collectors.toList()));
    when(this.searchRepositoryMock.getCurrentTable(companyId))
        .thenReturn(fromTableMock);
    when(recordMock.get(TYPEID)).thenReturn(financialTypeId);
    when(this.searchRepositoryMock.getDeviceData(
        ArgumentMatchers.anyList(),
        ArgumentMatchers.anyList(),
        any(),
        any(),
        eq(searchRequest.getPageSize()),
        eq(searchRequest.getPage()),
        eq(searchRequest.getSortCriterias()),
        eq(fromTableMock),
        ArgumentMatchers.anyList(),
        eq(Optional.empty()),
        eq(this.dslContextMock)))
        .thenReturn(deviceDataResultMock);

    return searchRequest;
  }```
wqlqzqxt

wqlqzqxt1#

为什么不起作用

你这是在嘲笑我

when(deviceDataResultMock.iterator()).thenReturn(resultIterator);

但是你没有嘲笑Result.spliterator(),或者至少我没有看到它,这就是Result.stream()所称的,它只是Collection.stream()

default Stream<E> stream() {
    return StreamSupport.stream(spliterator(), false);
}

因此,您还必须模拟spliterator()方法,可能还需要模拟其他一些方法!或者,让Mockito调用default方法:
Can you make mockito (1.10.17) work with default methods in interfaces?

关于嘲笑的一般评论

我不相信模仿jOOQAPI是一个好主意。jOOQAPI是巨大的,你可能会忘记模仿这个或那个方法,正如这个问题所恰当地表明的。在你目前的设置下,你打算 * 每次 * 你计划一个新的专栏时 * 都更新你的模仿吗?例如,你正在这样做:

when(recordMock.get(DEVICEID.getName()).thenReturn(deviceId);

如果列被重命名了呢?或者另一个列被投影了呢?你必须更新这个测试。这感觉像是一件很麻烦的事,而且很容易出错。
虽然jOOQ本身有JDBC mocking capabilities,但请考虑该手册页上的粗体免责声明:
免责声明:使用这个jOOQAPI模拟JDBC连接的一般想法是使用一个非常简单的JDBC抽象来提供快速的解决方案、注入点等。(包括复杂的状态转换、事务、锁定等)。一旦您有此需求,请考虑使用实际的数据库产品进行集成测试,而不是在MockDataProvider内部实现测试数据库
在使用数据库时,通常最好采用运行集成测试的方法,有关详细信息,请参阅以下资源:

当然,如果您不信任jOOQ,您可以编写一些烟雾测试来确保jOOQ正常工作(jOOQ是一个外部依赖项)。但是jOOQ单元和集成测试是庞大的,所以一般来说,您应该能够信任像ResultRecord这样的核心类型来为您做正确的事情。您真正想要测试的是您的查询正确性,您只能针对实际数据库示例进行集成测试。

相关问题