One really useful option in SpecFlow, which maybe most people will never need, is the ability to intercept input and potentially transform it. So the example I have is, we want to include tokens wrapped in { }. These braces will include a token which can then be replaced by a “real” value. Let’s assume {configuration.XXX} means get the value XXX from the configuration file (App.config).
With this use case in mind, let’s assume we have a feature that looks like this
Feature: Transformer Tests Scenario: Transform a number Given The value {configuration.someValue1} Scenario: Transform a table Given The values | One | Two | | {configuration.someValue1} | {configuration.someValue2} |
We’re going to hard code our transformer to simple change configuration.someValue1 to Value1 and configuration.someValue2 to Value2, but ofcourse the real data could be read from the App.Config or generated in some more useful way.
Our step file for the above feature file, might look like this
[Given(@"The value (.*)")] public void GivenTheValue(string s) { s.Should().Be("Value1"); } [Given(@"The values")] public void GivenTheValues(Table table) { foreach (var row in table.Rows) { var i = 1; foreach (var rowValue in row.Values) { rowValue.Should().Be($"Value{i}"); i++; } } }
We create a class, usually stored in the Hooks folder which looks like the following, where we include methods with the StepArgumentTransformation attribute, meaning these methods are call for the given type to do something with the step argument.
[Binding] public class StepTransformer { private string SimpleTransformer(string s) { switch (s) { case "{configuration.someValue1}": return "Value1"; case "{configuration.someValue2}": return "Value2"; default: return s; } } [StepArgumentTransformation] public string Transform(string input) { return SimpleTransformer(input); } [StepArgumentTransformation] public Table Transform(Table input) { foreach (var row in input.Rows) { foreach (var kv in row) { row[kv.Key] = SimpleTransformer(kv.Value); } } return input; } }
This is a very simple example of such code, what we’d do in a real world is create some more advanced transformer code and inject that via the constructor but the basic Transform method would look much like they are here.