Code_Noob
Code_Noob

Reputation: 77

How to convert a SpecFlow table into a Dictionary<string, List<string>> c#

I have to following SpecFlow code:

    And I get and validate parameters
        | ParameterName| Value | Answers | Mandatory | Meta | Modified | ReadOnly | Submit | SubmitValues | Tag    |
        | SurName      |       |         | true      |      | false    | false    | true   |              | input  |
        | Name         |       |         | true      |      | false    | false    | false  |              | input  |
.....

And i want this table to convert it into a Dictionary<string, List<string>>, the head columns will be the keys and the rest of the information will be the values. I hardcoded some values:

Dictionary<string, List<string>> dictionary = new Dictionary<string, List<string>>();
dictionary.Add("ParameterName", new List<string> {"SurName", "Name", "Age"});
dictionary.Add("Value", new List<string> { "", "", "" });
dictionary.Add("Answers", new List<string> { "", "", "" });
dictionary.Add("Mandatory", new List<string> { "true", "true", "true" });
dictionary.Add("Meta", new List<string> { "", "", "" });
dictionary.Add("Modified", new List<string> { "false", "false", "false" });
dictionary.Add("ReadOnly", new List<string> { "false", "false", "false" });
dictionary.Add("Submit", new List<string> { "true", "false", "true" });
dictionary.Add("SubmitValues", new List<string> { "", "", "" });
dictionary.Add("Tag", new List<string> { "input", "input", "select" });

But the actual table has a lot of values and i need to do this for all of them, and they might change, that's why i don't need a hardcoded dictionary. How can I do this?

Upvotes: 0

Views: 8871

Answers (3)

Sud
Sud

Reputation: 25

It's too late to answer this question but probably might be helpful for others.

The better way to handle such data in collection should be in format List>.

Following extension method should help in this regard-

    public static List<Dictionary<string, string>> ConvertToDictionaryList(this Table dt)
    {
        var lstDict = new List<Dictionary<string, string>>();

        if (dt!=null)
        {
            var headers = dt.Header;

            foreach (var row in dt.Rows)
            {
                var dict = new Dictionary<string, string>();
                foreach (var header in headers)
                {
                    dict.Add(header, row[header]);
                }

                lstDict.Add(dict);
            }
        }

        return lstDict;
    }

But if you still want to use Dictionary>, then you can use following snippet

    public static List<Dictionary<string, string>> ConvertToDictionaryList(this Table dt)
    {
        var lstDict = new Dictionary<string, List<string>>();

        if (dt != null)
        {
            var headers = dt.Header;

            foreach (var row in dt.Rows)
            {
                foreach (var header in headers)
                {
                    if (lstDict.ContainsKey(header))
                    {
                        lstDict[header].Add(row[header]);
                    }
                    else
                    {
                        lstDict.Add(header, new List<string> { row[header] });
                    }
                }
            }
        }

        return lstDict;

    }

Upvotes: 0

Andreas Willich
Andreas Willich

Reputation: 5835

You could also use the CreateSet extension method from the TechTalk.SpecFlow.Assist namespace.
Have a look at the documentation here: http://specflow.org/documentation/SpecFlow-Assist-Helpers/

Small example:

CreateSet is an extension method off of Table that will convert the table data to a set of objects. For example, if you have the following step:

Given these products exist
    | Sku              | Name             | Price |
    | BOOK1            | Atlas Shrugged   | 25.04 |
    | BOOK2            | The Fountainhead | 20.15 |

You can convert the data in the table to a set of objects like so:

[Given(@"Given these products exist")]
public void x(Table table)
{
    var products = table.CreateSet<Product>();
    // ...
}

Upvotes: 0

Gy&#246;rgy Kőszeg
Gy&#246;rgy Kőszeg

Reputation: 18023

In such a dictionary the retrieval of the same row is quite awkward (you should index the Value lists)...

Instead, I would create a List<TestParameters> where TestParameters class contains a row with normal strongly typed properties:

public class TestParameters
{
    public string ParameterName { set; set; }
    public int Value { set; set; }
    public bool Mandatory { set; set; }
    // etc.
}

So now you have somewhere a test step like this:

[Given(@"I get and validate parameters")]
public void GetParameters(Table parameters)
{
}

Simply replace the Table with your more specific type:

[Given(@"I get and validate parameters")]
public void GetParameters(List<TestParameters> parameters)
{
}

And just define a Table->List transformation step in a helper class:

[Binding]
public class Transformations
{
    [StepArgumentTransformation]
    public List<TestParameters> GetTestParameters(Table table)
    {
        return table.Rows.Select(row => new TestParameters
        {
            // string prop
            ParameterName = row["ParameterName"],

            // int prop
            Value = !String.IsNullOrEmpty(row["Value"]) ? Int32.Parse(row["Value"]) : 0,

            // bool prop
            Mandatory = row["Mandatory"]?.ToLowerInvariant() == "true"

            // TODO: other properties
        }).ToList();
    }
}

Of course, the result of the transformation can be Dictionary<string, List<string>>, too, if you really insist to that...

Upvotes: 2

Related Questions