@testset scoping

Hi,
I’m belatedly getting around to updating some private packages to 0.7 (and then to 1.0). I ran into some instances of implicit globals in the package tests and I’ve mostly gotten rid of them and gotten my head round all the scoping changes. However, I still have a few places where I’m getting implicit global variables warning that I can’t understand. The warnings all look like

Warning: Deprecated syntax `implicit assignment to global variable `x1``.
│ Use `global x1` instead.
└ @ none:0

for a few different variable names. The test structure for the package (which consists of an umbrella module with a few submodules) is as follows:

@testset "master testset" begin
     @testset "submodule1" begin
          include("submodule1_tests.jl")
    end
    @testset "submodule2" begin
          include("submodule2_tests.jl")
    end
.
.
.
end

where the tests for each submodule might contain nested @testsets. All my remaining implicit global variable warnings come from cases where a variable is created inside a testset in one submodule and then the same variable name is reused inside another testset. For example I might have

x1 = foo()
@test x1==1

inside the submodule1 tests and then never refer to x again inside that testset. Then in another submodule’s tests I might do

x1 = bar()
@test x1 == 4.5

with x1 not being used anywhere else in any of the tests. If I change x1 to a new name in the second testset, the implicit global warning goes away. I’m confused as to why this is happening. As far as I understand, @testset introduces a new local scope, so the two uses of x1 above should have nothing to do with each other. Unfortunately I haven’t been able to reduce this to a MWE, which is doubly confusing as the following (which I thought was equivalent to my actual use case in terms of scoping) runs without warnings in 0.7

julia> using Test

julia> @testset "master" begin
         @test 1 == 1
         @testset "inner1" begin
         y = ones(10)
         @test y == ones(10)
         @testset "inner2" begin
             y = zeros(2)
             @test y == zeros(2)
         end
         end
         @testset "inner3" begin
            y = [1;2;3]
            @test y == [1;2;3]
         end
         end
Test Summary: | Pass  Total
master        |    4      4
Test.DefaultTestSet("master", Any[DefaultTestSet("inner1", Any[DefaultTestSet("inner2", Any[], 1, false)], 1, false), DefaultTestSet("inner3", Any[], 1, false)], 1, false)

Anyone have any idea what’s going on here? I’m stumped.

Thanks!

2 Likes

Surprising, perhaps, but documented in the manual:

  include(path::AbstractString)

  Evaluate the contents of the input source file in the global scope of
  the containing module.
2 Likes

Ah yes, of course. That was the culprit! Thanks very much. I’ve been bitten by that once before, also testing related. I should have remembered. Hopefully twice is enough to get it properly into my head. Thanks again.

Patrick

It is quite common to use modules in the tests. For example for your first example:

@testset "master testset" begin
     @testset "submodule1" begin
          include("submodule1_tests.jl")
    end
    [...]
end

the file submodule1_tests.jl could define a module SubModule1Test or similar:

module SubModule1Test
    # tests
end
3 Likes

Interesting. That sounds like a good idea. Thanks.