如何将空值输入到 specflow 步骤定义 table

How to input null-value into specflow step definition table

如何通过 table 在 Specflow 中输入空值?

我们来看一个过于简单的例子:

When a tire is attached to a car
| CarId | TireModel      | FabricationDate | Batch |
| 1     | Nokian Hakka R | 2015-09-1       |       |

Batch 列中的空字符串被 specflow 解释为文本,因此是空字符串。是否有特殊语法将该列标记为空?

我认为 null 没有特殊的语法,我认为您必须自己处理转换。 value retrievers have been revised in the v2 branch 并且您可以通过注销标准字符串值检索器并注册您自己的实现来处理此问题,该实现查找一些特殊语法和 returns null.

在当前的 1.9.* 版本中,尽管我认为您只需要检查空字符串并且 return 自己为 null。

我只是选择使用简单的扩展方法逐案执行此操作。

在处理程序中,我转换传入的示例值参数并调用 NullIfEmpty()

用法示例

AndICheckTheBatchNumber(string batch) {
    batch = batch.NullIfEmpty();
    //use batch as null how you intended
}

扩展方法

using System;

namespace Util.Extensions
{
    public static class StringExtensions
    {        
        public static string NullIfEmpty(this string str)
        {
            if (string.IsNullOrEmpty(str))
            {
                return null;
            }
            return str;
        }
    }
}

您可以创建自己的 IValueRetriever 并将默认值替换为您的

public class StringValueRetriver : IValueRetriever
{
    public bool CanRetrieve(KeyValuePair<string, string> keyValuePair, Type targetType, Type propertyType)
    {
        return propertyType == typeof(string);
    }

    public object Retrieve(KeyValuePair<string, string> keyValuePair, Type targetType, Type propertyType)
    {
        return string.IsNullOrEmpty(keyValuePair.Value) ? null : keyValuePair.Value;
    }
}

您场景中的一些步骤

[BeforeScenario]
public void BeforeScenario()
{
    Service.Instance.ValueRetrievers.Unregister<TechTalk.SpecFlow.Assist.ValueRetrievers.StringValueRetriever>();
    Service.Instance.ValueRetrievers.Register(new StringValueRetriver());
}

旧语法:

[BeforeScenario]
public void BeforeScenario()
{
    var defaultStringValueRetriever = Service.Instance.ValueRetrievers.FirstOrDefault(vr => vr is TechTalk.SpecFlow.Assist.ValueRetrievers.StringValueRetriever);
    if (defaultStringValueRetriever != null)
    {
        Service.Instance.UnregisterValueRetriever(defaultStringValueRetriever);
        Service.Instance.RegisterValueRetriever(new StringValueRetriver());
    }
}

从 SpecFlow 3 开始,在您的步骤 class 中,您可以只输入以下代码。在功能文件中,只需像这样放置空值。现在,当您使用 CreateSet 函数时,它将被正确反序列化。

Id | Value
1  | <null> 

[Binding]
public static class YourStepClass
{
    [BeforeTestRun]
    public static void BeforeTestRun()
    {
        Service.Instance.ValueRetrievers.Register(new NullValueRetriever("<null>"));
    }
}

结合答案,我做了以下事情:

using TechTalk.SpecFlow;
using TechTalk.SpecFlow.Assist;
using TechTalk.SpecFlow.Assist.ValueRetrievers;

namespace Util.Extensions
{
    public class NullValueComparer : IValueComparer
    {
        private readonly string _nullValue;
        public NullValueComparer(string nullValue)
        {
            _nullValue = nullValue;
        }

        public bool CanCompare(object actualValue)
        {
            return actualValue is null || actualValue is string;
        }

        public bool Compare(string expectedValue, object actualValue)
        {
            if (_nullValue == expectedValue)
            {
                return actualValue == null;
            }
            return expectedValue == (string)actualValue;
        }
    }
}

并像这样引用它:

    [Binding]
    public class MyStepDefinitions
    {
        private MyTestDto _testDto;
        private AnotherDtoFromElsewhere _actual;

        [BeforeScenario]
        public void BeforeTestRun()
        {
            Service.Instance.ValueRetrievers.Register(new NullValueRetriever("<null>"));
            Service.Instance.ValueComparers.Register(new NullValueComparer("<null>"));
        }

       [When(@"Some test with table:")]
        public void WhenTestWithTable(Table table)
        {
            _testDto = table.CreateInstance<MyTestDto>();
            var actual = new AnotherDtoFromElsewhere();
            table.CompareToInstance(actual);
        }

       [Then(@"X should match:")]
        public void ThenShouldMatch(Table table)
        {
            table.CompareToInstance(_actual);
        }
    }