You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

在Cucumber中解码DataTable时如何正确上报自定义异常?

在Cucumber 7.18 + Java 21中DataTable转换时保留自定义错误消息的方法

问题场景

使用Cucumber 7.18和Java 21时,希望测试场景的错误消息足够直观,方便测试工程师快速定位问题,但DataTable转换过程中自定义异常消息会丢失,仅显示通用转换失败提示。

例如测试场景中第三行CODE列存在非法非整数值:

Given My system produces the following entries:
  | NAME     | ORC |          CODE | EPT | EFL | TIME   |
  | AFR89YB  | A   |          4455 | DEP | 100 | -00:10 |
  | AFR89YC  | B   |          4455 | DEP | 100 | -00:10 |
  | AFR89YD  | C   | Illegal value | DEP | 100 | -00:10 |
  | ...      | ... |           ... | ... | ... | ...    |

通过@DataTableType注解注册转换方法:

@DataTableType
public MySystemEntry mySystemEntry(Map<String, String> entry) {
    return MySystemEntry.builder()
            .entry(entry)
            .build();
}

在MySystemEntry的Builder中添加验证规则,非法值时抛出自定义IllegalArgumentException:

public class MySystemEntry {
   // ...
   public static Builder builder() {
      return new Builder();
   }

   public static class Builder {
      // ...
      public Builder entry(Map<String, String> entry) {
          // ...
          String value = entry.get("CODE");
          if (notANumber(value)) {
              throw new IllegalArgumentException("Value " + value + " is illegal for Column 'CODE'.");
          }
          // ...
          return this;
      }
      // ...
   }
}

但实际运行时,自定义消息丢失,日志仅显示:

Step failed
io.cucumber.datatable.CucumberDataTableException: 'java.util.List<com.my-application.MySystemEntry>' could not transform
| NAME     | ORC |          CODE | EPT | EFL | TIME   |
| AFR89YB  | A   |          4455 | DEP | 100 | -00:10 |
| AFR89YC  | B   |          4455 | DEP | 100 | -00:10 |
| AFR89YD  | C   | Illegal value | DEP | 100 | -00:10 |
| ...      | ... |           ... | ... | ... | ...    |

    at io.cucumber.datatable.DataTableType.transform(DataTableType.java:158)
    ...
    at ✽.Given My system produces the following entries: (file:///D:/dev/java/my-application/src/test/resources/features/my-system-works.feature:26)
Caused by: io.cucumber.core.backend.CucumberInvocationTargetException
    at io.cucumber.java.Invoker.doInvoke(Invoker.java:73)
    ...

测试工程师无法快速定位错误,需逐一排查数据。

解决方案

要保留自定义错误消息,需调整异常抛出的时机与方式:

1. 在@DataTableType方法中捕获并重新抛出异常

在注册的转换方法里,捕获Builder抛出的异常,补充行信息后重新抛出,确保自定义消息被保留:

@DataTableType
public MySystemEntry mySystemEntry(Map<String, String> entry) {
    try {
        return MySystemEntry.builder()
                .entry(entry)
                .build();
    } catch (IllegalArgumentException e) {
        String rowInfo = String.format("Row with NAME '%s' has invalid data: ", entry.get("NAME"));
        throw new IllegalArgumentException(rowInfo + e.getMessage(), e);
    }
}

2. 实现TableTransformer接口做精细控制

若需要更精准的行号提示,可实现TableTransformer接口,在遍历行时处理异常:

public class MySystemEntryTableTransformer implements TableTransformer<List<MySystemEntry>> {
    @Override
    public List<MySystemEntry> transform(DataTable table) throws CucumberException {
        List<Map<String, String>> rows = table.asMaps();
        List<MySystemEntry> entries = new ArrayList<>();
        for (int i = 0; i < rows.size(); i++) {
            Map<String, String> row = rows.get(i);
            try {
                entries.add(MySystemEntry.builder().entry(row).build());
            } catch (IllegalArgumentException e) {
                throw new CucumberDataTableException(
                    String.format("Error in row %d: %s", i + 2, e.getMessage()), // 行号+2是因为表头占一行
                    e
                );
            }
        }
        return entries;
    }
}

然后在步骤定义类中注册该转换器:

@DefaultParameterTransformer
@DefaultDataTableEntryTransformer
@DefaultDataTableCellTransformer
public Object transformer(Object fromValue, Type toValueType) {
    Configuration configuration = new Configuration();
    return configuration.getTransformerRegistry().getTransformer(toValueType).transform(fromValue);
}

@DataTableType
public TableTransformer<List<MySystemEntry>> mySystemEntryTableTransformer() {
    return new MySystemEntryTableTransformer();
}

关键原理

Cucumber转换DataTable时,会将底层异常包装为CucumberInvocationTargetException,最终转为CucumberDataTableException。直接在@DataTableType方法中抛出带明确消息的异常,或捕获后重新抛出时保留原始消息,Cucumber会将这些消息包含在最终输出中,让测试工程师直接看到错误原因与位置。

验证方式

调整代码后运行测试,日志将显示包含自定义消息的错误提示,例如:Error in row 4: Value Illegal value is illegal for Column 'CODE'.

内容的提问来源于stack exchange,提问作者jmgonet

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.16 03:11:19