Custom Parameters
- C#
- JavaScript
- Go
We saw how SpecFlow captures certain parts of our steps and passes them as arguments to our step definitions. Output parameters declared as {int} will be passed as integers. Output parameters declared as {word} and {string} will be passed as strings.
Sometimes it’s useful to be able to pass more meaningful arguments to our step definitions. This is easy with custom parameter types. Let’s try this out with our Coordinate class.
Create a new class in the Shouty.Specs project called Conversions and add the following code:
[Binding]
public class Conversions
{
[StepArgumentTransformation(@"(\d+), (\d+)")]
public Coordinate ConvertCoordinate(int xCoord, int yCoord)
{
return new Coordinate(xCoord, yCoord);
}
}
The [StepArgumentTransformation] attribute defines a regular expression to capture our location notation, passes the matching values to the method, which then returns a new Coordinate object.
Change your step definition from:
[Given(@"{word} is at {int}, {int}")]
public void GivenPersonIsAt(string name, int xCoord, int yCoord)
{
shoutyContext.Shouty.SetLocation(name, new Coordinate(xCoord, yCoord));
}
to
[Given("{word} is at {Coordinate}")]
public void GivenPersonIsAt(string name, Coordinate coordinate)
{
shoutyContext.Shouty.SetLocation(name, coordinate);
}
Run SpecFlow and all scenarios should still be green.
Move the other StepArgumentTransformation method you created earlier to convert the data table
also to the newly created Conversions class.
You can now add different StepArgumentTransformations which will deal with place names rather than coordinates, e.g. North Pole is at 0, 0. See if you can add the transformation and change Lucy’s location to the North Pole.
We’ve seen how Cucumber captures parts of our steps and passes them as arguments into step definitions. Placeholders like {int} become numbers, and {word} / {string} become strings.
Sometimes it’s useful to pass richer, domain-specific objects instead of primitive types. In Cucumber.js we can do this with custom parameter types. Let’s try this with our Coordinate class.
Create a new file features/support/parameter_types.js and add:
const { defineParameterType } = require('@cucumber/cucumber')
const Coordinate = require('../../lib/coordinate')
defineParameterType({
regexp: /(\d+), (\d+)/,
transformer: (x, y) => new Coordinate(parseInt(x, 10), parseInt(y, 10)),
name: 'coordinate'
})
This tells Cucumber how to turn text like 0, 900 into a Coordinate instance.
Now change your step definition from:
Given('{word} is at {int}, {int}', function (name, x, y) {
this.shouty.setLocation(name, new Coordinate(x, y))
})
to:
Given('{word} is at {coordinate}', function (name, coordinate) {
this.shouty.setLocation(name, coordinate)
})
Run Cucumber — all scenarios should still be green, but your step definitions are now working with proper Coordinate objects instead of raw numbers.
You can now add more custom parameter types to support, for example, place names rather than coordinates:
"North Pole"→new Coordinate(0, 0)"Downtown"→ some other coordinate
Try adding such a parameter type and updating Lucy’s location in the feature file to use the place name instead of raw coordinates.
Godog does not support custom parameters.