ttutisani/Xunit.Gherkin.Quick

Scenario outlines don't push values into DocString objects

Closed this issue · 7 comments

Same issue as the previous one with DataTables, but with DocString objects, which could be widely used for queries, parsers, etc.

For example, we have this outline:

Scenario Outline: Parse int variables
  When code block is sent
    """
    int <a> = 5;
    int <b> = 8;
    """
  Then parsed variables are <a> and <b>
  Examples:
    | a     | b      |
    | five  | eight  |

Then, this code:

[When(@"code block is sent")]
public void CodeBlockIsSent(DocString codeBlock)
{
    System.Console.WriteLine(codeBlock.Content);
}

[Then(@"parsed variables are {} and {}")]
public void ParsedVariablesAreAnd(string a, string b)
{
    System.Console.WriteLine($"A: {a}, B: {b}");
}

Produces:

int <a> = 5;
int <b> = 8;
A: five, B: eight

Expected:

int five = 5;
int eight = 8;
A: five, B: eight

@ttutisani Hi! I've fixed it in this pull request. Would be extremely grateful if you took a look and created a new release with these commits!

Hi @farost. Thanks for the work!

I cannot approve it because I don't think it's right for DocString to ingest example parameters by default. I know the DataTable behaves this way, and I kind of regret approving that, too.
So, the right way would be to have difference between a DocString that does not ingest example values (that will be a default behavior), and a DocString that ingests parameter values. I see two options for that.

Option 1: I think this can be simpler - to add an annotation to DocString indicating it's not a default behavior.

[When(@"code block is sent")]
public void CodeBlockIsSent([IngectExampleValues] DocString codeBlock)
{
    System.Console.WriteLine(codeBlock.Content);
}

Option 2: this will be more work and only do this if the first option is impossible - introduce a new argument type to indicate it's not a default behavior.

[When(@"code block is sent")]
public void CodeBlockIsSent(DocStringFromExample codeBlock)
{
    System.Console.WriteLine(codeBlock.Content);
}

Optional note: if you can, apply the same fix for DataTable. If not, that change will happen in the future.

I've been thinking about it since I commented, and I wanted to provide an additional explanation:

Scenario outline is supposed to inject values into the scenario steps but not into scenario step parameters. Scenario step is like a code, and scenario step parameter (DocString or DataTable) is like a constant inside the step (such as string). That is where the difference is. Outline is to re-generate the code, but it should leave constants untouched by default.

Thank you for the quick answer!

Well, I don't have rich experience with BDD, but I know that popular BDD frameworks for other languages (like Cucumber for Java) consider it as a normal behavior. This way, the project I am working on right now depends on this feature and uses such substitutions for many behavior tests based on queries (you can imagine an sql query insert into <name>).

I decided not to wait until the ideological approval as a DocString for me is a multi-line alternative to strings, which pushes me to use DocStrings, and it was a surprise that these "multi-line strings" are not affected by the examples. And I find a case of using "" within a DocString within a Scenario Outline with a "value" inside the Examples table pretty rare to be unintentional.

However, I agree that having a choice between these two behaviors is a good thing, so I'll try discovering what could be done to implement one of your ideas.

Sure, and let me know if you get stuck. I don't remember all the internals, but if I find time, I will dig more.

Congratulations, 4.4.0 is published. You can upgrade your Nuget to have this change.
Thanks for your contribution!

@ttutisani Thank you for your help, it works for my project!