Skip to content

Commit ea1cbf8

Browse files
authored
Always run the test_end_expr, even if the test throws an exception. (#163)
* Always run the test_end_expr, even if the test throws an exception. Put the test_end_expr running in a try/finally. Also adds a debugv log for running the test_end_expr (For testing this, we hard-code the number of expected test failures in DontPass.jl)
1 parent 8d63cbd commit ea1cbf8

File tree

2 files changed

+39
-3
lines changed

2 files changed

+39
-3
lines changed

src/ReTestItems.jl

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,8 @@ will be run.
166166
Can be used to load packages or set up the environment. Must be a `:block` expression.
167167
- `test_end_expr::Expr`: an expression that will be run after each testitem is run.
168168
Can be used to verify that global state is unchanged after running a test. Must be a `:block` expression.
169+
The `test_end_expr` is evaluated whether a testitem passes, fails, or errors. If the
170+
`testsetup` fails, then the `test_end_expr` is not run.
169171
- `gc_between_testitems::Bool`: If `true`, a full garbage collection (GC) will be run after each test item is run.
170172
Defaults to `nworkers > 1`, i.e. `true` when running with multiple worker processes, since multiple worker processes
171173
cannot coordinate to trigger Julia's GC, and it should not be necessary to invoke the GC directly if running without
@@ -955,11 +957,17 @@ end
955957
# when `runtestitem` called directly or `@testitem` called outside of `runtests`.
956958
function runtestitem(
957959
ti::TestItem, ctx::TestContext;
958-
test_end_expr::Expr=Expr(:block), logs::Symbol=:eager, verbose_results::Bool=true, finish_test::Bool=true,
960+
test_end_expr::Union{Nothing,Expr}=nothing, logs::Symbol=:eager, verbose_results::Bool=true, finish_test::Bool=true,
959961
)
960962
if should_skip(ti)::Bool
961963
return skiptestitem(ti, ctx; verbose_results)
962964
end
965+
if test_end_expr === nothing
966+
has_test_end_expr = false
967+
test_end_expr = Expr(:block)
968+
else
969+
has_test_end_expr = true
970+
end
963971
name = ti.name
964972
log_testitem_start(ti, ctx.ntestitems)
965973
ts = DefaultTestSet(name; verbose=verbose_results)
@@ -1024,8 +1032,13 @@ function runtestitem(
10241032
# environment = Module()
10251033
@debugv 1 "Running test item $(repr(name))$(_on_worker())."
10261034
_, stats = @timed_with_compilation _redirect_logs(logs == :eager ? DEFAULT_STDOUT[] : logpath(ti)) do
1027-
with_source_path(() -> Core.eval(Main, mod_expr), ti.file)
1028-
with_source_path(() -> Core.eval(Main, test_end_mod_expr), ti.file)
1035+
# Always run the test_end_mod_expr, even if the test item fails / throws
1036+
try
1037+
with_source_path(() -> Core.eval(Main, mod_expr), ti.file)
1038+
finally
1039+
has_test_end_expr && @debugv 1 "Running test_end_expr for test item $(repr(name))$(_on_worker())."
1040+
with_source_path(() -> Core.eval(Main, test_end_mod_expr), ti.file)
1041+
end
10291042
nothing # return nothing as the first return value of @timed_with_compilation
10301043
end
10311044
@debugv 1 "Done running test item $(repr(name))$(_on_worker())."

test/integrationtests.jl

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1068,6 +1068,29 @@ end
10681068
@test length(failures(results_with_end)) 1
10691069
end
10701070
end
1071+
mutable struct AtomicCounter{T}; @atomic x::T; end
1072+
@testset "test_end_expr always runs, even if testitem throws" begin
1073+
@testset "DontPass.jl package" begin
1074+
# Test that even though the tests in DontPass will fail, the test_end_expr will
1075+
# still run.
1076+
end_expr_count = AtomicCounter(0)
1077+
test_end_expr = quote
1078+
@info "RUNNING"
1079+
@atomic $end_expr_count.x += 1
1080+
end
1081+
dont_pass_results = with_test_package("DontPass.jl") do
1082+
runtests(; nworkers=0, test_end_expr)
1083+
end
1084+
@test !all_passed(dont_pass_results)
1085+
@show n_passed(dont_pass_results)
1086+
@show length(failures(dont_pass_results))
1087+
@show length(errors(dont_pass_results))
1088+
Test.print_test_results(dont_pass_results)
1089+
# This is the total number of testitems in DontPass.jl, minus those with
1090+
# nonexistent testsetups, or errors in the testsetup.
1091+
@test @atomic(end_expr_count.x) == 7
1092+
end
1093+
end
10711094

10721095
@testset "Replace workers when we hit memory threshold" begin
10731096
using IOCapture

0 commit comments

Comments
 (0)