# @test\_throws UndefVarError f(x::A)=x

**URL:** <https://discourse.julialang.org/t/test-throws-undefvarerror-f-x-a-x/112497>\
**Category:** General Usage\
**Tags:** testing\
**Created:** [April 4, 2024, 4:18am UTC](https://discourse.julialang.org/t/test-throws-undefvarerror-f-x-a-x/112497 "2024-04-04T04:18:43Z")\
**Posts on this page:** 4\
**Page:** 1

<div class="post-metadata">

**Author:** ![CameronBieganek](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/cameronbieganek/32/6915_2.png) [@CameronBieganek](https://discourse.julialang.org/u/CameronBieganek)\
**Post date:** [April 4, 2024, 4:18am UTC](https://discourse.julialang.org/t/test-throws-undefvarerror-f-x-a-x/112497/1 "2024-04-04T04:18:44Z")

</div>

With a fresh Julia session:

```julia-repl
julia> using Test

julia> @test_throws UndefVarError foo(x::A)=x
ERROR: UndefVarError: `A` not defined

```

Should this be a passing test? I don’t quite get why the `UndefVarError` escapes the `@test_throws`.

(My actual code is much more complicated and involves a macro I wrote, but I think my issue boils down to this example.)

---

<div class="post-metadata">

**Author:** ![WschW](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/wschw/32/6575_2.png) [@WschW](https://discourse.julialang.org/u/WschW)\
**Post date:** [April 4, 2024, 5:29am UTC](https://discourse.julialang.org/t/test-throws-undefvarerror-f-x-a-x/112497/2 "2024-04-04T05:29:20Z")

</div>

This throws the exception before the test actually runs.

I think you would need to use `eval` to get the function to be defined when the test is being run

---

<div class="post-metadata">

**Author:** ![CameronBieganek](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/cameronbieganek/32/6915_2.png) [@CameronBieganek](https://discourse.julialang.org/u/CameronBieganek)\
**Post date:** [April 4, 2024, 12:25pm UTC](https://discourse.julialang.org/t/test-throws-undefvarerror-f-x-a-x/112497/3 "2024-04-04T12:25:33Z")

</div>

> [@WschW](#):
>
> This throws the exception before the test actually runs.

Well, that’s fairly obvious. 😉 But I don’t really understand why—the order of operations is not what I would expect.

The expression `foo(x::A) = x` shouldn’t throw an `UndefVarError` until the expression is actually evaluated. For example, this does not throw an error:

```julia-repl
julia> if false
           foo(x::A) = x
       else
           1
       end
1

```

Interestingly, this leads to an even more perverse example with `@test_throws`:

```julia
julia> @test_throws UndefVarError begin
           if false
               foo(x::A) = x
           else
               1
           end
       end
ERROR: UndefVarError: `A` not defined

```

Or a similar example with `@test`:

```julia-repl
julia> @test begin
           if false
               foo(x::A) = x
               true
           else
               true
           end
       end
ERROR: UndefVarError: `A` not defined

```

My understanding is that the `@test_throws` macro should expand before `foo(x::A) = x` is evaluated, and the `@test_throws` macro expands to some kind of try-catch block. Note that a basic try-catch block works as expected:

```julia-repl
julia> try
           foo(x::A) = x
       catch
           println("hello world")
       end
hello world

```

So, let’s take a closer look at what `@test_throws` expands to. After re-typesetting the output of `@macroexpand` in my editor to make it more readable, the output of `@macroexpand @test_throws UndefVarError f(x::A)=x` is

```julia
quote
    Test.do_test_throws(
        begin
            try
                Test.Returned(
                    $(Expr(:(=), :(foo(x::A)), quote x end)),
                    Test.nothing,
                    $(QuoteNode(:(#= REPL[8]:1 =#)))
                )
            catch var"#24#_e"
                if UndefVarError != Test.InterruptException && var"#24#_e" isa Test.InterruptException
                    Test.rethrow()
                end
                Test.Threw(var"#24#_e", Test.nothing, $(QuoteNode(:(#= REPL[8]:1 =#))))
            end
        end,
        $(QuoteNode(:(foo(x::A) = begin
            x
        end))),
        UndefVarError
    )
end

```

But I don’t know enough about `Test` internals to be able to interpret that…

---

<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:** [April 4, 2024, 5:18pm UTC](https://discourse.julialang.org/t/test-throws-undefvarerror-f-x-a-x/112497/4 "2024-04-04T17:18:43Z")

</div>

Ah, this is because it’s creating a closure, even with the named function syntax, as it uses a local scope. And closures implicitly create structs ahead of time. In other words, the `@macroexpand` is ok, but the problem comes at the next step, in lowering and you can see the problem (albeit hard to read) with `Meta.@lower`.

Or perhaps more clearly, this function errors _upon definition_, not upon execution:

```julia
julia> function test()
           return (::not_defined) -> 2
       end
ERROR: UndefVarError: `not_defined` not defined

```

And similarly, this more clearly shows that the problem is happening at definition-time:

```julia
julia> function test()
           @test_throws UndefVarError (::not_defined) -> 2
       end
ERROR: UndefVarError: `not_defined` not defined

```

If you were to do this with something that’s not a closure, it works as you expect:

```julia
julia> @test_throws UndefVarError Base.sum(::not_defined) = 2
Test Passed
      Thrown: UndefVarError

```
