@testset scoping


#1

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

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.

#3

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


#4

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

#5

Interesting. That sounds like a good idea. Thanks.