Dean Barnes
Dean Barnes

Reputation: 2272

Boolean parameters for SpecFlow steps

In SpecFlow, I want to check for the presence of a string in a step definition and at the moment I am doing clunky things like this contrived example:

[Given(@"Foo ( bar)?")]
public void GivenFoo(string bar)
{
    if (bar == " bar")
    {
        // do bar
    }
}

However, I'd like to do something like this:

[Given(@"Foo ( bar)?")]
public void GivenFoo(bool bar)
{
    if (bar)
    {
        // do bar
    }
}

But I can't find out how, so is this possible and if so how?

Upvotes: 9

Views: 11617

Answers (3)

The Vermilion Wizard
The Vermilion Wizard

Reputation: 5405

You definitely can do that sort of thing, using a StepArgumentTransformation method. You still have to write the parser logic, but you can sequester it into a method who's only purpose is to perform that parsing.

Example feature file:

Feature: I win if I am Batman

Scenario: Happy
    Given I am the Batman
    Then I defeat the Joker

Scenario: Sad
    Given I am not the Batman
    Then I am defeated by the Joker

Specflow Bindings (C#):

[Binding]
public class IWinIfIAmBatmanFeature
{
    private bool iAmBatman;

    [StepArgumentTransformation(@"(am ?.*)")]
    public bool AmToBool(string value)
    {
        return value == "am";
    }

    [Given(@"I (.*) the Batman")]
    public void WhoAmI(bool amIBatman)
    {
        iAmBatman = amIBatman;
    }

    [StepArgumentTransformation(@"(defeat|am defeated by)")]
    public bool WinLoseToBool(string value)
    {
        return value == "defeat";
    }

    [Then(@"I (.*) the Joker")]
    public void SuccessCondition(bool value)
    {
        Assert.AreEqual(iAmBatman, value);
    }
}

The key factor is that the regex match in your Given clause is matched by the step argument transformation. So in I (.*) the Batman, if the capture matches the regex in the argument for the StepArgumentTransformation, as it does in the attribute for AmToBool then that is the transformation that gets used.

Upvotes: 7

thecodefish
thecodefish

Reputation: 388

Based on your question and the comments to Jakub's answer, it looks like you are trying to write a single Step that can cover multiple user journeys through your site. SpecFlow isn't really designed for this, and it's probably an indication that you should try and improve the structure of your scenarios/features.

To answer your question directly, I don't believe there is a way to deduce boolean values based on the existence of certain strings in your step definition.

If you want to persist down this route, then your original example is probably your best bet.

I would recommend that you don't take this approach, however, and instead look at restructuring your step definitions so that you can chain them together, and re-use them across scenarios. I'm actually struggling to think of an example step definition that would fit your solution.

An example of a multi-step approach might look like this:

Given I have logged in as an existing user //1
And I have started my 6-step registration process //2
And I have filled in valid address values on step 1 //3
And I have left the fields blank on step 2 //4
... etc
When I save my registration

And your steps would be:

  1. navigate to login page, log in as valid user
  2. navigate to step 1
  3. fill in fields with valid input, click 'next'
  4. click 'next'

You just need to ensure that each step is as independent of the others as possible, so you could replace one step with a subtly different one (for a new scenario) without affecting the others.

With this approach you can still end up with complex (and potentially quite verbose) scenarios, but I think that's a better solution than trying to be clever and pack as much into a single step definition. You'll probably end up with scenarios that are unreadable, and the code will probably be a pain to read/maintain as well.

Upvotes: 1

Jakub Konecki
Jakub Konecki

Reputation: 46008

Are you looking for:

[Given(@"I do something (times) times")]
public void GivenIDoSomething(int times)
{
}

Otherwise this seems to suffice

[Given(@"I do something twice")]
public void GivenIDoSomethingTwice()
{
}

EDIT

I think that instead of if statement in the step you actually want to separate steps.

Upvotes: 0

Related Questions