13
votes

How can I input a null value in Specflow through a table?

Let's look at an overly simplistic example:

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

The empty string in the Batch column is interpreted as text by specflow and as such, empty string. Is there a special syntax to mark that column as null?

4

4 Answers

18
votes

You can create your own IValueRetriever and replace default one with yours

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;
    }
}

Some where in your scenario steps

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

older syntax:

[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());
    }
}
2
votes

I don't believe there is a special syntax for null and I think you'll have to just handle the conversion yourself. The value retrievers have been revised in the v2 branch and you might be able to handle this by deregistering the standard string value retriever and registering your own implementation which looks for some special syntax and returns null.

In the current 1.9.* version though I think you'll just have to check for empty string and return null yourself.

2
votes

From SpecFlow 3 on-wards, in your Steps class, you can just put the following code. And in the feature file just put null value like this. Now when you use the CreateSet function then it will be deserialized correctly.

Id | Value
1  | <null> 

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

I've just chosen to do this on a case by case manner using a simple extension method.

In the handler I convert the passed in example value parameter and call NullIfEmpty()

Example usage

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

Extension method

using System;

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