-
-
Notifications
You must be signed in to change notification settings - Fork 616
Display outline values instead of index in junit output #1459
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Display outline values instead of index in junit output #1459
Conversation
acoulton
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks @uuf6429, I've got a few comments plus there are some merge conflicts with master to resolve.
| <testcase name="Passed & Failed #1" classname="World consistency" status="failed" time="-IGNORE-VALUE-" file="features-DIRECTORY-SEPARATOR-World.feature"> | ||
| <testcase name="Passed & Failed (value: 5, result: 16)" classname="World consistency" status="failed" time="-IGNORE-VALUE-" file="features-DIRECTORY-SEPARATOR-World.feature"> | ||
| <failure message="Then I must have 16: Failed asserting that 15 matches expected '16'."/> | ||
| </testcase> | ||
| <testcase name="Passed & Failed #2" classname="World consistency" status="passed" time="-IGNORE-VALUE-" file="features-DIRECTORY-SEPARATOR-World.feature"/> | ||
| <testcase name="Passed & Failed #3" classname="World consistency" status="failed" time="-IGNORE-VALUE-" file="features-DIRECTORY-SEPARATOR-World.feature"> | ||
| <testcase name="Passed & Failed (value: 10, result: 20)" classname="World consistency" status="passed" time="-IGNORE-VALUE-" file="features-DIRECTORY-SEPARATOR-World.feature"/> | ||
| <testcase name="Passed & Failed (value: 23, result: 32)" classname="World consistency" status="failed" time="-IGNORE-VALUE-" file="features-DIRECTORY-SEPARATOR-World.feature"> | ||
| <failure message="Then I must have 32: Failed asserting that 33 matches expected '32'."/> | ||
| </testcase> | ||
| <testcase name="Another Outline #1" classname="World consistency" status="passed" time="-IGNORE-VALUE-" file="features-DIRECTORY-SEPARATOR-World.feature"/> | ||
| <testcase name="Another Outline #2" classname="World consistency" status="passed" time="-IGNORE-VALUE-" file="features-DIRECTORY-SEPARATOR-World.feature"/> | ||
| <testcase name="Another Outline (value: 5, result: 15)" classname="World consistency" status="passed" time="-IGNORE-VALUE-" file="features-DIRECTORY-SEPARATOR-World.feature"/> | ||
| <testcase name="Another Outline (value: 10, result: 20)" classname="World consistency" status="passed" time="-IGNORE-VALUE-" file="features-DIRECTORY-SEPARATOR-World.feature"/> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't use junit at the moment but I know when I've used Jenkins in the past there was reporting that identified changes in individual tests over time - should we be worried about a risk that renaming the tests would break people's reports / workflows?
src/Behat/Behat/Output/Node/Printer/JUnit/JUnitScenarioPrinter.php
Outdated
Show resolved
Hide resolved
|
@carlos-granados very little, I think we're in agreement that changing the string content of the output is not a BC break so it just needs the constructor BC break fixing and merge conflicts resolved |
|
I've missed the last comments on this, I'll finish the remaining parts then. |
…line-values-instead-of-index-in-junit
| <testcase name="Another Outline #1" classname="World consistency" status="passed" time="-IGNORE-VALUE-" file="features-DIRECTORY-SEPARATOR-World.feature"/> | ||
| <testcase name="Another Outline #2" classname="World consistency" status="passed" time="-IGNORE-VALUE-" file="features-DIRECTORY-SEPARATOR-World.feature"/> | ||
| <testcase name="Another Outline (value: 5, result: 15)" classname="World consistency" status="passed" time="-IGNORE-VALUE-" file="features-DIRECTORY-SEPARATOR-World.feature"/> | ||
| <testcase name="Another Outline (value: 10, result: 20)" classname="World consistency" status="passed" time="-IGNORE-VALUE-" file="features-DIRECTORY-SEPARATOR-World.feature"/> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've come to realise something else. At work we create custom reports that reuse some of this functionality (title, example values etc).
We realised that the nicest solution (in our opinion) is to replace placeholders in the title - instead of add #<number> or in this case (<example values>).
Consider this feature:
feature:
Scenario Outline: <count> items should <passOrFail>
When I have <count> items
Then I should <passOrFail>
Examples:
| count | passOrFail |
| 0 | pass |
| 1 | pass |
| 2 | fail |- Currently, the result will be:
The number is not particularly useful.
<count> items should <passOrFail> #1 <count> items should <passOrFail> #2 <count> items should <passOrFail> #3 - With this PR, it would look like:
This is more useful, but not very readable and easily/unavoidably verbose
<count> items should <passOrFail> (count: 0, passOrFail: pass) <count> items should <passOrFail> (count: 1, passOrFail: pass) <count> items should <passOrFail> (count: 2, passOrFail: fail) - With my latest proposal:
Couldn't get any better. :)
0 items should pass 1 items should pass 2 items should fail
I think the 3rd would be the best overall approach, but I've a feeling this is not supported in gherkin though (although I guess it's not contradicting it either). What do you think @stof, @ciaranmcnulty?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I like the idea of the third approach (it's similar to how e.g. it.each( works in jest / vitest).
Off the top of my head I don't know how feasible it is with gherkin syntax - although presumably could find a placeholder string that didn't contain anything gherkin considers to be special characters.
The other question would be what you do if the title doesn't contain placeholders - would you try to detect that and append the values as in this PR, or would you stick with the current #0 etc suffix, or something else?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The other question would be what you do if the title doesn't contain placeholders - would you try to detect that and append the values as in this PR, or would you stick with the current #0 etc suffix, or something else?
I was hoping I wouldn't have to answer that. 😆
When I think about it, it might make sense to add the numbering when the title already exists - it would be backward compatible and somewhat unsurprising.
private $outlineTitles = [];
private function buildExampleName(ExampleNode $scenario): string
{
$currentOutline = $this->outlineStoreListener->getCurrentOutline($scenario);
$title = $this->replacePlaceholders($scenario->getOutlineTitle(), $scenario->getTokens());
$number = $this->outlineTitles[$title] ?? 0;
$this->outlineTitles[$title] = $number + 1;
if ($number > 0) {
$title .= " #$number";
}
if ($currentOutline === $this->lastOutline) {
$this->outlineTitles = [];
}
return $title;
}There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That could work quite well, so it becomes a definitely-BC update path:
- If you do nothing, you'll get the same test names as before (including that the numbers are inconsistent between initial and re-run?)
- But to get consistent - and clearer - naming, you just have to reword your scenario outlines to include placeholders
That's a really nice idea if you can find a syntax for it that works in gherkin. Using <title> would seem logical as it follows the pattern of how the parameters are referenced in the steps within the outline. But might be risky (now or in future) because of that.
I don't think {} has any special meaning in gherkin, so that might be a possibility...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
so it becomes a definitely-BC update path
Exactly.
But might be risky (now or in future) because of that.
If I didn't misunderstand, it is supported/implemented in cucumber already: cucumber/common#2149 and cucumber/cucumber-js#267. The request here seems to lend credence to that too: https://youtrack.jetbrains.com/issue/IDEA-320963/Cucumber-example-variable-usage-in-scenario-outline-title
On the whole, I think I'd go for the <...> syntax since it seems to also be what people there were expecting.
I see mixed signals in Behat though: #1024
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh perfect, if cucumber is already using the tags like that for this purpose then that's exactly what we need. There's also an example of it in cucumber/gherkin.
If I've understood right, most of the mixed signals in #1024 look to me like they're specific to the pretty output format (where I can see there's no logical place to do the substitution in the current output, because it only prints the Scenario Outline block once and just renders the results into and below the Examples: table).
The suggestion this should be implemented in Gherkin is probably right, but:
- I'm not sure why this comment is linking to
OutlineNode::getKeywordas I'm pretty sure that will (correctly) always just returnScenario Outline. - It can't change the return of
OutlineNode::getTitle()because that needs to be the title that represents all the examples e.g. without replacing any placeholders, so that e.g. the pretty formatter can use it as above.
I actually think the logical place to do this is inside ExampleNode. That is the class that's responsible for replacing placeholders in the step definitions, so replacing placeholders in the title there as well feels sensible.
ExampleNode already has a getOutlineTitle which currently just returns the parent title as-is. I can't find any usages of that method in behat - it could of course be used by other consumers. I don't know if we'd consider changing the string content a BC break - the safest option of course would be to add a new getOutlineTitleWithPlaceholders (with a better name 😆) and perhaps deprecate the existing getOutlineTitle.
The other advantage of doing it in ExampleNode is that when it's created by OutlineNode we presumably know which index it is in the gherkin file - I think filtering what will actually run comes later than parsing. So we could pass that into ExampleNode as well and use that to append a consistent number to the end of the title which would also then solve the JUnit bug even if people don't put placeholders into their titles.
WDYT?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I also feel the best place to put it would be in ExampleNode. I'm a bit hesitant with the semantics though.
getTitle- this feels like it should return the definitive title, e.g. to be shown in reports and so on. In the ideal world, I think this should be the one replacing placeholders and adding numbers for deduplication.getOutlineTitle- Internally (e.g. even in gherkin), it seems that there shouldn't be a concept of a scenario outline - instead they should be flattened into regular scenarios. With that in mind, I think the "outline title" should be the original (parent?) title - since that parent is the "scenario outline".getOutlineTitleWithPlaceholders(& co.) - I would go for such a method if we want to be absolutely BC safe. That said, I do feel that the majority of end users would rather have the BC break than the current approach, but that's my hypothesis.
PS: with regards to getTitle, if it did behave like that, #1470 might have been avoided. I'd appreciate @cavo789's thoughts on this as well.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The challenge is getTitle is the title of the "example" and is currently the content of the table row for the example e.g. 1 | 5 | 4 and existing formatters rely on it
Regarding collapsing scenario and scenario outline - that could also be valid : gherkin now treats them as synonyms. But again existing formatters display them differently.
Maybe we should move this to an issue in gherkin to keep the discussion visible & clear?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've updated the PR to fix conflicts and apply the last review suggestions, so that is can be "frozen" while a discussion can take place in behat/gherkin. Done: Behat/Gherkin#270
…line-values-instead-of-index-in-junit
…it (#1682) Previously, when a feature file contained scenarios with `Example` nodes the junit report would append an index to each testcase name to differentiate them (e.g. `<testcase name="Some scenario outline #1"`, `<testcase name="Some scenario outline #2`, etc). These indices were dynamically generated based on the examples that actually ran. As a result, on a `--rerun` the names would start from `#1` in sequence and be inconsistent with the numbering of the first execution. This makes it difficult to compare reports between each test run, for example to link a passing rerun to the previous failure. With this change, examples are numbered consistently based on the order they appear in the feature file. This fixes #1448. Additionally, we also now support placeholders in the Scenario Outline title. This allows users to include some or all of the values from the Examples: table in each `<testcase` name for additional clarity. This matches the behaviour of the official cucumber runners. This PR builds on work done by @uuf6429 in #1459 and in particular the implementation of the numbering & placeholder replacement that he contributed in Behat/Gherkin#270 and Behat/Gherkin#271.
Replaces "example name #N" with "example name (XX)" in JUnit output.
Closes #1448