-
-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add --retry option to retry failed tests as part of the same run (#920)
* Add feature file from PR 895 to start work on retry functionality * Initial spec for --retry option * Add another test for --retry flag, make new tests pass * Squash some commits Redo the commit I just reverted but with the file I intended to include the first time * Rebase onto master * Allow for --retry option in configuration Add retry_attempts method to configuration base class Add Retry formatter and specs for same Remove files attempting to implement --retry with a formatter - bad idea Add wip tag to prevent --retry features from killing the build Actually run Travis build against active branch Fix tiny grammatical error. Closes #914. * Update scenarios to look like @mattwynne's suggestion * Initial specs for retry filter - they test if it works at all, basically Change Retry filter to have attribute :configuration and first pass at setting up a listener Reorganize spec file Finish adding tests for re-running flaky test cases - all but one pass Fix spec that said to test what happens when a test case passes but actually didn't make sure it did pass * Add consistently failing scenario to test cases Define steps for the retry feature * Correct # of retries * Refactor test case * Make method private * Extract retry_required? method * Move steps for retry filter into other file * Correct block style
- Loading branch information
Showing
11 changed files
with
244 additions
and
7 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -12,14 +12,11 @@ rvm: | |
branches: | ||
only: | ||
- master | ||
- resolve-issue-882 | ||
- v1.3.x-bugfix | ||
|
||
before_install: | ||
- gem update bundler | ||
|
||
notifications: | ||
email: | ||
- [email protected] | ||
webhooks: | ||
urls: # gitter | ||
- https://webhooks.gitter.im/e/dc010332f9d40fcc21c4 | ||
email: false |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
@wip | ||
Feature: Retry failing tests | ||
|
||
Retry gives you a way to get through flaky tests that usually pass after a few runs. | ||
This gives a development team a way forward other than disabling a valuable test. | ||
|
||
- Specify max retry count in option | ||
- Output information to the screen | ||
- Output retry information in test report | ||
|
||
Questions: | ||
use a tag for flaky tests? Global option to retry any test that fails? | ||
|
||
Background: | ||
Given a scenario "Flakey" that fails once, then passes | ||
And a scenario "Shakey" that fails twice, then passes | ||
And a scenario "Solid" that passes | ||
And a scenario "No Dice" that fails | ||
|
||
Scenario: | ||
When I run `cucumber -q --retry 1` | ||
Then it should fail with: | ||
""" | ||
4 scenarios (2 passed, 2 failed) | ||
""" | ||
|
||
Scenario: | ||
When I run `cucumber -q --retry 2` | ||
Then it should pass with: | ||
""" | ||
4 scenarios (3 passed, 1 failed) | ||
""" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
Given /^a scenario "([^\"]*)" that fails once, then passes$/ do |name| | ||
write_file "features/#{name}.feature", | ||
<<-FEATURE | ||
Feature: #{name} | ||
Scenario: #{name} | ||
Given it fails once, then passes | ||
FEATURE | ||
|
||
write_file "features/step_defnitions/#{name}_steps.rb", | ||
<<-STEPS | ||
Given(/^it fails once, then passes$/) do | ||
$#{name.downcase} ||= 0 | ||
$#{name.downcase} += 1 | ||
expect($#{name.downcase}).to eql 2 | ||
end | ||
STEPS | ||
end | ||
|
||
Given /^a scenario "([^\"]*)" that fails twice, then passes$/ do |name| | ||
write_file "features/#{name}.feature", | ||
<<-FEATURE | ||
Feature: #{name} | ||
Scenario: #{name} | ||
Given it fails twice, then passes | ||
FEATURE | ||
|
||
write_file "features/step_definitions/#{name}_steps.rb", | ||
<<-STEPS | ||
Given(/^it fails twice, then passes$/) do | ||
$#{name.downcase} ||= 0 | ||
$#{name.downcase} += 1 | ||
expect($#{name.downcase}).to eql 3 | ||
end | ||
STEPS | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
require 'cucumber/core/filter' | ||
require 'cucumber/running_test_case' | ||
require 'cucumber/events/bus' | ||
require 'cucumber/events/after_test_case' | ||
|
||
module Cucumber | ||
module Filters | ||
class Retry < Core::Filter.new(:configuration) | ||
|
||
def test_case(test_case) | ||
configuration.on_event(:after_test_case) do |event| | ||
next unless retry_required?(test_case, event) | ||
|
||
test_case_counts[test_case] += 1 | ||
event.test_case.describe_to(receiver) | ||
end | ||
|
||
super | ||
end | ||
|
||
private | ||
|
||
def retry_required?(test_case, event) | ||
event.test_case == test_case && event.result.failed? && test_case_counts[test_case] < configuration.retry_attempts | ||
end | ||
|
||
def test_case_counts | ||
@test_case_counts ||= Hash.new {|h,k| h[k] = 0 } | ||
end | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,79 @@ | ||
require 'cucumber' | ||
require 'cucumber/filters/retry' | ||
require 'cucumber/core/gherkin/writer' | ||
require 'cucumber/configuration' | ||
require 'cucumber/core/test/case' | ||
require 'cucumber/core' | ||
require 'cucumber/events' | ||
|
||
describe Cucumber::Filters::Retry do | ||
include Cucumber::Core::Gherkin::Writer | ||
include Cucumber::Core | ||
include Cucumber::Events | ||
|
||
let(:configuration) { Cucumber::Configuration.new(:retry => 2) } | ||
let(:test_case) { Cucumber::Core::Test::Case.new([double('test steps')], double('source').as_null_object) } | ||
let(:receiver) { double('receiver').as_null_object } | ||
let(:filter) { Cucumber::Filters::Retry.new(configuration, receiver) } | ||
let(:fail) { Cucumber::Events::AfterTestCase.new(test_case, double('result', :failed? => true, :ok? => false)) } | ||
let(:pass) { Cucumber::Events::AfterTestCase.new(test_case, double('result', :failed? => false, :ok? => true)) } | ||
|
||
it { is_expected.to respond_to(:test_case) } | ||
it { is_expected.to respond_to(:with_receiver) } | ||
it { is_expected.to respond_to(:done) } | ||
|
||
context "general" do | ||
before(:each) do | ||
filter.with_receiver(receiver) | ||
end | ||
|
||
it "registers the :after_test_case event" do | ||
expect(configuration).to receive(:on_event).with(:after_test_case) | ||
filter.test_case(test_case) | ||
end | ||
end | ||
|
||
context "passing test case" do | ||
it "describes the test case once" do | ||
expect(test_case).to receive(:describe_to).with(receiver) | ||
filter.test_case(test_case) | ||
configuration.notify(pass) | ||
end | ||
end | ||
|
||
context "failing test case" do | ||
it "describes the test case the specified number of times" do | ||
expect(receiver).to receive(:test_case) {|test_case| | ||
configuration.notify(fail) | ||
}.exactly(3).times | ||
|
||
filter.test_case(test_case) | ||
end | ||
end | ||
|
||
context "flaky test cases" do | ||
|
||
context "a little flaky" do | ||
it "describes the test case twice" do | ||
results = [fail, pass] | ||
expect(receiver).to receive(:test_case) {|test_case| | ||
configuration.notify(results.shift) | ||
}.exactly(2).times | ||
|
||
filter.test_case(test_case) | ||
end | ||
end | ||
|
||
context "really flaky" do | ||
it "describes the test case 3 times" do | ||
results = [fail, fail, pass] | ||
|
||
expect(receiver).to receive(:test_case) {|test_case| | ||
configuration.notify(results.shift) | ||
}.exactly(3).times | ||
|
||
filter.test_case(test_case) | ||
end | ||
end | ||
end | ||
end |