【问题标题】:Custom datatable transformer for cucumber-jvmcucumber-jvm 的自定义数据表转换器
【发布时间】:2015-02-05 08:06:47
【问题描述】:

我想在黄瓜中创建自定义数据表转换器。这就是我的功能的样子:

Given board
| o | _ | _ |
| o | _ | _ |
| o | _ | _ |

我想把它放到自定义对象中。假设它看起来像这样:

class Board {

    private List<List<String>> board;

    public Board(List<List<String>> board) {
        this.board = board;
    }

}

我的步骤定义应该是这样的:

@Given("^board$")
public void board(Board board) throws Throwable {
    // todo
}

步骤定义适用于DataTable 类和List&lt;List&lt;String&gt;&gt;

@Given("^board$")
public void board(DataTable board) throws Throwable {
    // this works fine
}

这也很好用

@Given("^board$")
public void board(List<List<String>> board) throws Throwable {
    // this also works fine
}

我试图在互联网上找到解决方案,但没有任何成功。我也尝试创建Transformer,但正如我所见,它仅适用于字符串(我想在输入时使用 Datatable 或 List>):

class BoardTransformer extends Transformer<Board> {

    @Override
    public Board transform(String value) {
        // TODO Auto-generated method stub
        return null;
    }

}

【问题讨论】:

  • 你的 cucumber-JVM 版本是多少?
  • 我用的是1.2.2版本。
  • 运气好能找到解决方案吗?
  • 你真的应该升级你的黄瓜!

标签: java cucumber cucumber-jvm


【解决方案1】:

在 cucumber 3.x 中,您可以使用 TypeRegistryConfigurer 通知 Cucumber 它应该如何从 DataTable 创建 Board 对象。因为要将整个表转换为单个对象,所以必须使用 TableTransformer 而不是 TableCellTransformerTableEntryTransformerTableRowTransformer

您可以将TypeRegistryConfigurer 放置在粘合路径上的任何位置。

package io.cucumber.java.test;

import io.cucumber.core.api.TypeRegistryConfigurer;
import io.cucumber.core.api.TypeRegistry;
import io.cucumber.datatable.DataTableType;
import io.cucumber.datatable.TableTransformer;

import java.util.List;
import java.util.Locale;

import static java.util.Locale.ENGLISH;

public class TypeRegistryConfiguration implements TypeRegistryConfigurer {

    @Override
    public Locale locale() {
        return ENGLISH;
    }


    @Override
    public void configureTypeRegistry(TypeRegistry typeRegistry) {
        typeRegistry.defineDataTableType(new DataTableType(
            Board.class,
            (TableTransformer<Board>) table -> new Board(table.cells())));

    }

    static class Board {

        private final List<List<String>> board;

        private Board(List<List<String>> board) {
            this.board = board;
        }
    }
}

【讨论】:

    【解决方案2】:

    在旧版本的黄瓜中,根据您所说的 1.2.2,您必须请求对象列表,因为数据表的每一行(从功能文件的角度来看)都被视为不同的对象,例如

    @Given("^board$")
    public void board(List<Board> board) throws Throwable {
        // process however you want
    }
    

    从 v3 开始,很多黄瓜在数据表方面发生了变化,例如从 XStream 切换到 Jackson

    但如前所述,请尽可能升级您的 Cucumber 版本

    【讨论】:

      【解决方案3】:

      如果可以的话

      @Given("^board$")
      public void board(List<List<String>> board) throws Throwable {
      ...
      

      你为什么不马上创建你的 Board 对象

      Board board2 = new Board(board);
      

      看来您不需要变压器。

      【讨论】:

      • 永远不会“需要”转换器,它只是更好更清晰,不会使代码与技术细节混淆。你的回答没有多大帮助......
      【解决方案4】:

      假设目标是将“讨厌的参数转换东西”与“实际测试代码”分开,这样我就可以在我的测试代码中使用漂亮的对象,我能想到的最好的就是利用Jackson ObjectMapper(或其他一些支持 Map to Object 的反序列化库)。

      例如:

      private ObjectMapper objectMapper = new ObjectMapper();
      
      @When("I do some thing with input dataTable")
      public void i_do_some_thing_with_input_dataTable(DataTable dataTable) {
          List<Map<String,String>> values = dataTable.asMaps(String.class, String.class);
          List<MyObject> inputs = values.stream().map(i -> objectMapper.convertValue(i,MyObject.class)).collect(Collectors.toList());
      
          inputs.forEach(i-> {
              //Do things with the input.
          });
      }
      

      您当然可以/应该将此转换包装在一些不错的服务类中,您可以在测试中注入/实例化。

      此代码假设如下:

      • 您正在使用带有标题的数据表
      • MyObject 中的字段名称与表中的标题对应
      • MyObject 为每个字段提供适当的 getter/setter。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多