mirror of
https://gitea.invidious.io/iv-org/shard-spectator.git
synced 2024-08-15 00:53:35 +00:00
Implement aggregate_failures
This commit is contained in:
parent
9a97596b84
commit
4c125d98d4
5 changed files with 100 additions and 2 deletions
|
@ -25,6 +25,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||
- Examples with failures or skipped during execution will report the location of that result. [#57](https://gitlab.com/arctic-fox/spectator/-/issues/57)
|
||||
- Support custom messages for failed expectations. [#28](https://gitlab.com/arctic-fox/spectator/-/issues/28)
|
||||
- Allow named arguments and assignments for `provided` (`given`) block.
|
||||
- Add `aggregate_failures` to capture and report multiple failed expectations. [#24](https://gitlab.com/arctic-fox/spectator/-/issues/24)
|
||||
|
||||
### Changed
|
||||
- `around_each` hooks wrap `before_all` and `after_all` hooks. [#12](https://github.com/icy-arctic-fox/spectator/issues/12)
|
||||
|
|
32
spec/spectator/aggregate_failures_spec.cr
Normal file
32
spec/spectator/aggregate_failures_spec.cr
Normal file
|
@ -0,0 +1,32 @@
|
|||
require "../spec_helper"
|
||||
|
||||
Spectator.describe Spectator do
|
||||
describe "aggregate_failures" do
|
||||
it "captures multiple failed expectations" do
|
||||
expect do
|
||||
aggregate_failures do
|
||||
expect(true).to be_false
|
||||
expect(false).to be_true
|
||||
end
|
||||
end.to raise_error(Spectator::MultipleExpectationsFailed, /2 failures/)
|
||||
end
|
||||
|
||||
it "raises normally for one failed expectation" do
|
||||
expect do
|
||||
aggregate_failures do
|
||||
expect(true).to be_false
|
||||
expect(true).to be_true
|
||||
end
|
||||
end.to raise_error(Spectator::ExpectationFailed)
|
||||
end
|
||||
|
||||
it "doesn't raise when there are no failed expectations" do
|
||||
expect do
|
||||
aggregate_failures do
|
||||
expect(false).to be_false
|
||||
expect(true).to be_true
|
||||
end
|
||||
end.to_not raise_error(Spectator::ExpectationFailed)
|
||||
end
|
||||
end
|
||||
end
|
|
@ -162,5 +162,20 @@ module Spectator::DSL
|
|||
macro is_not(expected)
|
||||
expect(subject).not_to(eq({{expected}}))
|
||||
end
|
||||
|
||||
# Captures multiple possible failures.
|
||||
# Aborts after the block completes if there were any failed expectations in the block.
|
||||
#
|
||||
# ```
|
||||
# aggregate_failures do
|
||||
# expect(true).to be_false
|
||||
# expect(false).to be_true
|
||||
# end
|
||||
# ```
|
||||
def aggregate_failures
|
||||
::Spectator::Harness.current.aggregate_failures do
|
||||
yield
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -2,7 +2,9 @@ require "./error_result"
|
|||
require "./example_failed"
|
||||
require "./example_pending"
|
||||
require "./expectation"
|
||||
require "./expectation_failed"
|
||||
require "./mocks"
|
||||
require "./multiple_expectations_failed"
|
||||
require "./pass_result"
|
||||
require "./result"
|
||||
|
||||
|
@ -66,6 +68,7 @@ module Spectator
|
|||
|
||||
@deferred = Deque(->).new
|
||||
@expectations = [] of Expectation
|
||||
@aggregate : Array(Expectation)? = nil
|
||||
|
||||
# Runs test code and produces a result based on the outcome.
|
||||
# The test code should be called from within the block given to this method.
|
||||
|
@ -75,14 +78,20 @@ module Spectator
|
|||
translate(elapsed + elapsed2, error || error2)
|
||||
end
|
||||
|
||||
def report(expectation : Expectation) : Nil
|
||||
def report(expectation : Expectation) : Bool
|
||||
Log.debug { "Reporting expectation #{expectation}" }
|
||||
@expectations << expectation
|
||||
|
||||
# TODO: Move this out of harness, maybe to `Example`.
|
||||
Example.current.name = expectation.description unless Example.current.name?
|
||||
|
||||
raise ExpectationFailed.new(expectation, expectation.failure_message) if expectation.failed?
|
||||
if expectation.failed?
|
||||
raise ExpectationFailed.new(expectation, expectation.failure_message) unless (aggregate = @aggregate)
|
||||
aggregate << expectation
|
||||
false
|
||||
else
|
||||
true
|
||||
end
|
||||
end
|
||||
|
||||
# Stores a block of code to be executed later.
|
||||
|
@ -91,6 +100,31 @@ module Spectator
|
|||
@deferred << block
|
||||
end
|
||||
|
||||
def aggregate_failures
|
||||
previous = @aggregate
|
||||
@aggregate = aggregate = [] of Expectation
|
||||
begin
|
||||
yield.tap do
|
||||
# If there's an nested aggregate (for some reason), allow the top-level one to handle things.
|
||||
check_aggregate(aggregate) unless previous
|
||||
end
|
||||
ensure
|
||||
@aggregate = previous
|
||||
end
|
||||
end
|
||||
|
||||
private def check_aggregate(aggregate)
|
||||
failures = aggregate.select(&.failed?)
|
||||
case failures.size
|
||||
when 0 then return
|
||||
when 1
|
||||
expectation = failures.first
|
||||
raise ExpectationFailed.new(expectation, expectation.failure_message)
|
||||
else
|
||||
raise MultipleExpectationsFailed.new(failures, "Got #{failures.size} failures from failure aggregation block")
|
||||
end
|
||||
end
|
||||
|
||||
# Yields to run the test code and returns information about the outcome.
|
||||
# Returns a tuple with the elapsed time and an error if one occurred (otherwise nil).
|
||||
private def capture : Tuple(Time::Span, Exception?)
|
||||
|
|
16
src/spectator/multiple_expectations_failed.cr
Normal file
16
src/spectator/multiple_expectations_failed.cr
Normal file
|
@ -0,0 +1,16 @@
|
|||
require "./example_failed"
|
||||
require "./expectation"
|
||||
|
||||
module Spectator
|
||||
# Exception that indicates more than one expectation from a test failed.
|
||||
# When raised within a test, the test should abort.
|
||||
class MultipleExpectationsFailed < ExampleFailed
|
||||
# Expectations that failed.
|
||||
getter expectations : Array(Expectation)
|
||||
|
||||
# Creates the exception.
|
||||
def initialize(@expectations : Array(Expectation), message : String? = nil, cause : Exception? = nil)
|
||||
super(nil, message, cause)
|
||||
end
|
||||
end
|
||||
end
|
Loading…
Reference in a new issue