cucumber-jvm 版本 3 替代简单 table 到 Map<String,String> 操作的设计模式

cucumber-jvm version 3 substitute design pattern for simple table to Map<String,String> operation

我正在探索 cucumber-jvm:3.0.0 中引入的新 io.cucumber.datatable.DataTable 支持。我安装了 cucumber-jvm:3.0.2。

我现有的 cucumber-jvm:2.4.0 项目使用了一个简单的设计模式,我将 table 传递到最后一个参数具有 Map 类型的步骤中。版本 3 不再支持此行为。

所以我创建了一个测试用例来模拟这个设计模式的替代方案。它有效,但返回的 Map 是不可修改的。我解决了这个问题,但有两个问题:

  1. 为什么返回的地图是immutable?我是否忽略了一个重要的设计原则?
  2. 有没有更简单的方法来实现我寻找替代设计模式的基本目标?

代码如下:

# h/t to https://github.com/cucumber/datatable-java/edit/master/datatable/src/test/java/io/cucumber/datatable/DataTableTypeRegistryTableConverterTest.java
Feature: Test simple DataTable converters  

  @simple_no_header_map_string_string
  Scenario: Convert a two column table to a Map
    Given a basic street address
      | streetAddress | 333 W Camden St |
      | cityName      | Baltimore       |
      | stateName     | MD              |
      | postalCode    | 21201           |
    When I specify Country "US"
    Then I can print the complete address 


package some.org.stuff.cucumberjvm302testbed;

import cucumber.api.java.en.Given;
import cucumber.api.java.en.Then;
import cucumber.api.java.en.When;

import io.cucumber.datatable.DataTable;
import io.cucumber.datatable.DataTable.TableConverter;
import io.cucumber.datatable.DataTableTypeRegistry;
import io.cucumber.datatable.DataTableTypeRegistryTableConverter;
import io.cucumber.datatable.TypeReference;

import java.lang.reflect.Type;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;

public class Cucumber302TestBedSteps {

    private Map<String,String> addressMap;

    private final DataTableTypeRegistry registry = new DataTableTypeRegistry(Locale.ENGLISH);
    private final TableConverter converter = new DataTableTypeRegistryTableConverter(registry);
    private static final Type MAP_OF_STRING_TO_STRING = new TypeReference<Map<String, String>>() {
    }.getType();

    @Given("^a basic street address$")
    public void aBasicStreetAddress(DataTable datatable) {
        //Here is the workaround to make addressMap mutable
        addressMap = new HashMap<String,String>(converter.convert(datatable, MAP_OF_STRING_TO_STRING)); 
    }

    @When("^I specify Country \"(.+)\"$")
    public void iSpecifyCountry(String inputCountry) {
        addressMap.put("country", inputCountry);
    }

    @Then("^I can print the complete address$")
    public void iCanPrintTheCompleteAddress() {
        System.out.println("\n\t" + addressMap.get("streetAddress"));
        System.out.println("\t" + addressMap.get("cityName"));
        System.out.println("\t" + addressMap.get("stateName"));
        System.out.println("\t" + addressMap.get("postalCode"));
        System.out.println("\t" + addressMap.get("country") + "\n");
    }
}

我看了。我确实实施了该解决方案,但我有一些初级测试人员,所以我正在寻找更简单的方法。

您可能会觉得这种模式更合您的口味:

private final Map<String,String> addressMap = new HashMap<>();

@Given("^a basic street address$")
public void aBasicStreetAddress(Map<String,String> address) {
    addressMap.putAll(address);
}

@When("^I specify Country \"(.+)\"$")
public void iSpecifyCountry(String inputCountry) {
    addressMap.put("country", inputCountry);
}

@Then("^I can print the complete address$")
public void iCanPrintTheCompleteAddress() {
    System.out.println("\n\t" + addressMap.get("streetAddress"));
    System.out.println("\t" + addressMap.get("cityName"));
    System.out.println("\t" + addressMap.get("stateName"));
    System.out.println("\t" + addressMap.get("postalCode"));
    System.out.println("\t" + addressMap.get("country") + "\n");
}

我们先将其定义为一个空映射,而不是在给定步骤中设置 addressMap。这确保始终存在合理的默认值。这使得步骤更加灵活,因为它们现在可以按任何顺序多次使用。诚然,在这种特定情况下价值不大,但通常非常有用。

然后在给定的步骤中我们将最后一个参数设置为Map<String,String> address。 Cucumber 会将 DataTable 转换为地图。我们使用 .putAll 将所有字段从 address 复制到 addressMap.

address 是不可变的,以防止通过具有副作用的方法修改原始输入。当稍后使用原始输入进行断言时,这是一种有用的机制。除非对象被显式复制,否则您可以相信它没有被修改。这使代码更易于阅读。

My existing cucumber-jvm:2.4.0 project makes use of a simple design pattern where I pass a table into a step whose last parameter has type Map. This behaviour is no longer supported in version 3.

此行为仍受支持。是什么让您认为不是?

private final DataTableTypeRegistry registry = new DataTableTypeRegistry(Locale.ENGLISH); private final TableConverter converter = new DataTableTypeRegistryTableConverter(registry); private static final Type MAP_OF_STRING_TO_STRING = new TypeReference>() { }.getType();

这里不需要这个。看看 TypeRegistryConfigurer。不过请记住,基本类型的地图和列表已内置支持。