For those who are unfamiliar, Specflow is an acceptance test framework that can be used to provide human readable, automated tests for .net. Automated testing is becoming more and more popular, offering real reductions in time and cost when compared with manual testing. One of the main benefits is it enables developers to automatically run repeatable tests, reliably whenever they need to, Improving the efficiency of the workflow.
When writing a Specflow .feature file, there will be a counterpart .feature.cs that is generated automatically along with it. This is what is actually executed at run time. Luckily you won't have to worry about maintaining it as whenever a changed is detected on the feature file it's .cs is automatically regenerated in the background.
A simple test in a feature file might look like this:
Scenario: A web page can be loadedGiven there is a valid internet connectionWhen making a get request to "example.com"Then the response status should be "200"
The step definition behind the When step will look something like this:
[When(@"making a get request to '(.*)'")]public void WhenMakingAGetRequestTo(string uri){Response = HttpClient.GetAsync(uri).GetAwaiter().GetResult();}
In the example above, the transformation between the information provided in the scenario and the step definition is a simple string. However there are situations where you might want to pass more complex data structures. For this Specflow provides tables. Say you have a simple user class:
public class User{private string FirstName;private string LastName;private int Age;private string Gender;public User(string firstName, string lastName, int age, string gender){FirstName = firstName;LastName = lastName;Age = age;Gender = gender;}}
and some data in a scenario that you want to create some User objects with.
Given the following users exist in the database:| FirstName | LastName | Age | Gender || John | Smith | 32 | Male || Sam | Smith | 26 | Female || Bob | White | 55 | Male |
This example doesn't need a custom step argument transformation, as the user class is only using basic C# data types, you can instead use the create functionality.
[Given(@"the following users exist in the database:")]public void GivenTheFollowingUsersExistInTheDatabase(Table table){var users = table.CreateSet();// ...}
However when the data gets more complex, you might have a custom class that contains a collection of another custom type, the create function won't provide for this out of the box. There are two options you can use to overcome this. The first option is that you can provide instances of a couple of interfaces for your custom class which you can find out more about here. Alternately if your situation is too complex for that, you can create a custom step argument transformation. Here I have a customer class that contains some basic information about a customer which contains a reference to another custom class.
public class Customer{ private string FirstName; private string LastName; private Company CustomerCompany;// ...}
Now you probably don't want to specify an entire company's data when creating a customer, in this situation a step argument transformation would be rather handy. One of the easiest ways is to give the customer in the Specflow table some kind of identifier for the custom type:
Given the following customer data exists:| First Name | Last Name | Company Name || Jess | Brown | The Tech Shop |
In the step argument transformation you can then use the identifier to get the reference you need:
[StepArgumentTransformation]public Customer TableToCustomer(Table table){ var row = table.Rows[0]; var company = Companies.FirstOrDefault(row["Company Name"]) return new Customer( row["First Name"], row[" Last Name"], company);}
With this you can now use your custom class type as the parameter for the corresponding step definition, rather than the default Specflow Table. You'll probably want to put your step argument transformations in their own file and the only consideration you need to take into account is that the class needs the same [Binding] annotation as a standard step definition class.