# Scope and structure for unit test files

**URL:** <https://discourse.julialang.org/t/scope-and-structure-for-unit-test-files/122278>\
**Category:** New to Julia\
**Tags:** question\
**Created:** [November 5, 2024, 10:19am UTC](https://discourse.julialang.org/t/scope-and-structure-for-unit-test-files/122278 "2024-11-05T10:19:43Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![world-peace](https://avatars.discourse-cdn.com/v4/letter/w/9f8e36/32.png) [@world-peace](https://discourse.julialang.org/u/world-peace)\
**Post date:** [November 5, 2024, 10:19am UTC](https://discourse.julialang.org/t/scope-and-structure-for-unit-test-files/122278/1 "2024-11-05T10:19:43Z")

</div>

I have a query about how to structure the contents of a unit test file.

In many cases, ideally, for each test we will have an independent scope. This is to prevent information leakage between different test cases.

The documentation suggests that the `@testset` macro is used to define a scope.

However, it also suggests the purpose of this macro serves a different purpose - to group tests into logical groups.

> The `@testset` macro can be used to group tests into _sets_ . All the tests in a test set will be run, and at the end of the test set a summary will be printed. If any of the tests failed, or could not be evaluated due to an error, the test set will then throw a `TestSetException` .

Here’s an example of how a typical `runTests.jl` file might be structured.

```julia
# runTests.jl

include("testComponentA.jl")
include("testComponentB.jl")

```

To run it, I use a short script, which lives in the same directory.

```julia
#!/usr/bin/bash
julia --project -e 'using Pkg; Pkg.test()'

```

Here’s how each of the individual test files might be structured. I didn’t make these files into modules by including `module ... end`. Possibly I should have.

Each component of the source code, for example a module which performs some self-contained function, has a corresponding file in the test directory containing its tests.

```julia
# testComponentA.jl
# this is not a module, maybe it should be

include("../src/ComponentA.jl")

using Main.ComponentAModule

using Test

@testset "ComponentAModuleTests" begin

    # this is a single unit test
    component = ComponentA()
    @test component.someFunction() == someValue

    # this is an independent unit test from the above
    # should it be part of the same test set?
    component2 = ComponentA()
    @test component2.someOtherFunction() == someOtherValue

    # information leakage: component != component2
    # easy to use `component` instead of `component2`
    # and thus make a mistake in test code

end

```

My question here being, is this the right use of `@testset` or should `@testset` be used to create and destroy scope for individual unit tests. (To prevent information leakage.)

Related to the above, is it possible to create a new scope using a `let` statement? Something like

```julia
let
    # put a single test here
end

```

I’m not sure if that is valid syntax, because the `let` is not associated with any value. When I tried it, it seemed to be valid however.

Perhaps a combination of both should be used?

---

<div class="post-metadata">

**Author:** ![lupemba](https://avatars.discourse-cdn.com/v4/letter/l/e5b9ba/32.png) [@lupemba](https://discourse.julialang.org/u/lupemba)\
**Post date:** [November 5, 2024, 10:38am UTC](https://discourse.julialang.org/t/scope-and-structure-for-unit-test-files/122278/2 "2024-11-05T10:38:12Z")

</div>

Have you tried to look at [GitHub - YingboMa/SafeTestsets.jl](https://github.com/YingboMa/SafeTestsets.jl)  
This package might solve your concern about leaking information. [DifferentialEquations.jl](https://github.com/SciML/DifferentialEquations.jl) uses the package to separate the tests into several files that can be run independent. [DifferentialEquations.jl/test/runtests.jl at master · SciML/DifferentialEquations.jl · GitHub](https://github.com/SciML/DifferentialEquations.jl/blob/master/test/runtests.jl)

---

<div class="post-metadata">

**Author:** ![Vasily\_Pisarev](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/vasily_pisarev/32/7929_2.png) [@Vasily\_Pisarev](https://discourse.julialang.org/u/Vasily_Pisarev)\
**Post date:** [November 5, 2024, 1:27pm UTC](https://discourse.julialang.org/t/scope-and-structure-for-unit-test-files/122278/3 "2024-11-05T13:27:24Z")

</div>

> [@world-peace](#):
>
> is it possible to create a new scope using a `let` statement?

First, if I am not mistaken, `@testset` evaluates its inner expression in a separate scope. At least, quick testing suggests so:

```julia
julia> @testset "Tests" begin
       x = 10
       @test 2.0 == 2
       end
Test Summary: | Pass Total Time
Tests | 1 1 0.0s
Test.DefaultTestSet("Tests", Any[], 1, false, false, true, 1.730812778488919e9, 1.73081277851395e9, false, "REPL[3]")

julia> x
ERROR: UndefVarError: `x` not defined

```

Second, any expression in Julia evaluates to a value. The value of `let ... end` expression is equal to the value of the last evaluated subexpression. You can check that following works perfectly fine:

```julia
let
    x = 1
    x + 1
end == 2

```

So,

```julia
@test let
    x = 2
    x^2 == 4
end

```

is perfectly valid.

---

<div class="post-metadata">

**Author:** ![sgaure](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/sgaure/32/14779_2.png) [@sgaure](https://discourse.julialang.org/u/sgaure)\
**Post date:** [November 5, 2024, 1:33pm UTC](https://discourse.julialang.org/t/scope-and-structure-for-unit-test-files/122278/4 "2024-11-05T13:33:09Z")

</div>

There are myriads of examples of usage of `Test.jl` in the source code of julia here: [julia/test at master · JuliaLang/julia · GitHub](https://github.com/JuliaLang/julia/tree/master/test)

---

<div class="post-metadata">

**Author:** ![mbauman](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mbauman/32/31082_2.png) [@mbauman](https://discourse.julialang.org/u/mbauman)\
**Post date:** [November 5, 2024, 2:17pm UTC](https://discourse.julialang.org/t/scope-and-structure-for-unit-test-files/122278/5 "2024-11-05T14:17:19Z")

</div>

You can also nest testsets:

```Julia
julia> @testset "outer" begin
           @testset "inner1" begin
               x = 2
               @test 1+1 == 2
           end
           @testset "inner2" begin
               y = 3
               @test 1+x == y
           end
       end
inner2: Error During Test at REPL[6]:8
  Test threw exception
  Expression: 1 + x == y
  UndefVarError: `x` not defined

```

Using `let` is fine, too — even if there are no “let bindings” you explicitly introduce, it’s still creating a scope block.
