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

如何在SpecFlow步骤定义表格中为未提供的列设置默认值

如何在SpecFlow步骤定义表格中为未提供的列设置默认值?

场景示例

特性文件(Feature File):

@regression @add-a-new-cat
Feature: Add a new cat
  As a User
  I should be able to add a cat

  # Vocabulary:
  # User: An authorized application user

  @positive @smoke-test
  Scenario: Add a new cat
    Given the User is authorized to add a new cat
    When the User adds new cat
    | CatName | Age | Breed  |
    | Kitty   | 5   | Indian |
    | Lucy   | 5   | Persian |
    Then the cat is added successfully

理想的步骤定义:

[When(@"the User adds new cat")]
public async void WhenTheUserAddsNewCatEndpointAsync(Table table)
{
    var addCats = table.CreateSet<CatDetails>();
    var request = new RestRequest("cats");
    request.AddBody(addCats);
    restResponse = await restSharpRetryDriver.restClient.ExecutePostAsync(request);
}

需求说明

当特性文件的数据表格未包含所有列时,需要为缺失的列自动填充默认值。比如表格只提供CatName和Age时,Breed列要自动使用预设的默认值。

已知的基础方案

方案一:遍历集合手动赋值

[When(@"the User adds new cat")]
public async void WhenTheUserAddsNewCatEndpointAsync(Table table)
{
    var addCats = table.CreateSet<CatDetails>();
    foreach (var row in addCats)
    {
        if (row.Breed == null)
        {
           row.Breed = "persian"; // 当特性文件未传入该列时赋值默认值
        }
    }
    var request = new RestRequest("cats");
    request.AddBody(addCats);
    restResponse = await restSharpRetryDriver.restClient.ExecutePostAsync(request);
}

方案二:在实体类的属性getter中设置默认值

public class AddCatSteps
{
    public class CatDetails
    {
        [TableAliases("Name", "CatName")]
        public string Name { get; set; }
        public int Age { get; set; }
        
        string _breed;
        public string Breed
        {
            get
            {
                return _breed ?? "newBreed";
            }
            set
            {
                _breed = value;
            }
        }
    }

    [When(@"the User adds new cat")]
    public async void WhenTheUserAddsNewCatEndpointAsync(Table table)
    {
        var addCats = table.CreateSet<CatDetails>();
        var request = new RestRequest("cats");
        request.AddBody(addCats);
        restResponse = await restSharpRetryDriver.restClient.ExecutePostAsync(request);
    }
}

以上两种方案在涉及多列需要设置默认值时,会产生大量重复代码,不够简洁,下面是更优的解决方案:


更优解决方案

方案三:利用实体类的默认构造函数初始化默认值

在CatDetails的构造函数中直接为属性设置默认值,SpecFlow的CreateSet<T>方法在创建实例时会调用默认构造函数,未被表格赋值的属性会保留构造函数中的默认值。

public class CatDetails
{
    [TableAliases("Name", "CatName")]
    public string Name { get; set; }
    public int Age { get; set; }
    public string Breed { get; set; }
    public string Color { get; set; } // 新增需要默认值的列

    // 默认构造函数初始化默认值
    public CatDetails()
    {
        Breed = "persian";
        Color = "white";
    }
}

步骤定义无需修改,保持最初的简洁写法即可:

[When(@"the User adds new cat")]
public async void WhenTheUserAddsNewCatEndpointAsync(Table table)
{
    var addCats = table.CreateSet<CatDetails>();
    var request = new RestRequest("cats");
    request.AddBody(addCats);
    restResponse = await restSharpRetryDriver.restClient.ExecutePostAsync(request);
}

方案四:自定义Table扩展方法,批量注入默认值

如果需要更灵活的默认值配置(比如不同场景用不同默认值),可以编写一个扩展方法,统一处理表格转换后的实体默认值填充:

public static class TableExtensions
{
    public static IEnumerable<T> CreateSetWithDefaults<T>(this Table table, Action<T> defaultInitializer) where T : new()
    {
        var items = table.CreateSet<T>();
        foreach (var item in items)
        {
            defaultInitializer(item);
        }
        return items;
    }
}

使用时在步骤定义中指定默认值逻辑:

[When(@"the User adds new cat")]
public async void WhenTheUserAddsNewCatEndpointAsync(Table table)
{
    var addCats = table.CreateSetWithDefaults<CatDetails>(cat => 
    {
        cat.Breed = cat.Breed ?? "persian";
        cat.Color = cat.Color ?? "white";
        // 其他列的默认值逻辑
    });
    var request = new RestRequest("cats");
    request.AddBody(addCats);
    restResponse = await restSharpRetryDriver.restClient.ExecutePostAsync(request);
}

这种方式的优势是可以针对不同步骤场景设置不同的默认值,同时避免在实体类中硬编码默认值,更具灵活性。

方案五:使用AutoMapper映射表格数据并设置默认值

如果项目中已经使用AutoMapper,可以通过配置映射规则来处理默认值:

  1. 配置AutoMapper映射:
var configuration = new MapperConfiguration(cfg =>
{
    cfg.CreateMap<TableRow, CatDetails>()
       .ForMember(dest => dest.Breed, opt => opt.MapFrom(src => src["Breed"] ?? "persian"))
       .ForMember(dest => dest.Color, opt => opt.MapFrom(src => src["Color"] ?? "white"))
       .ForMember(dest => dest.Name, opt => opt.MapFrom(src => src["CatName"] ?? src["Name"]));
});
IMapper mapper = configuration.CreateMapper();
  1. 步骤定义中使用AutoMapper转换表格数据:
[When(@"the User adds new cat")]
public async void WhenTheUserAddsNewCatEndpointAsync(Table table)
{
    var addCats = table.Rows.Select(row => mapper.Map<CatDetails>(row));
    var request = new RestRequest("cats");
    request.AddBody(addCats);
    restResponse = await restSharpRetryDriver.restClient.ExecutePostAsync(request);
}

这种方式适合复杂的映射场景,同时可以统一管理所有实体的映射规则和默认值逻辑。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.25 16:43:57