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 是不可修改的。我解决了这个问题,但有两个问题:
- 为什么返回的地图是immutable?我是否忽略了一个重要的设计原则?
- 有没有更简单的方法来实现我寻找替代设计模式的基本目标?
代码如下:
# 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。不过请记住,基本类型的地图和列表已内置支持。
我正在探索 cucumber-jvm:3.0.0 中引入的新 io.cucumber.datatable.DataTable 支持。我安装了 cucumber-jvm:3.0.2。
我现有的 cucumber-jvm:2.4.0 项目使用了一个简单的设计模式,我将 table 传递到最后一个参数具有 Map 类型的步骤中。版本 3 不再支持此行为。
所以我创建了一个测试用例来模拟这个设计模式的替代方案。它有效,但返回的 Map 是不可修改的。我解决了这个问题,但有两个问题:
- 为什么返回的地图是immutable?我是否忽略了一个重要的设计原则?
- 有没有更简单的方法来实现我寻找替代设计模式的基本目标?
代码如下:
# 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。不过请记住,基本类型的地图和列表已内置支持。