# Base.@kwdef breaks in tests only

**URL:** https://discourse.julialang.org/t/base-kwdef-breaks-in-tests-only/91356
**Category:** General Usage
**Tags:** testing, constructors
**Created:** [December 7, 2022, 10:37am UTC](https://discourse.julialang.org/t/base-kwdef-breaks-in-tests-only/91356 "2022-12-07T10:37:48Z")
**Posts on this page:** 3
**Page:** 1

<div class="post-metadata">

### Author: ![eott-siz](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/eott-siz/32/44936_2.png) [@eott-siz](https://discourse.julialang.org/u/eott-siz)
#### Post date: [December 7, 2022, 10:37am UTC](https://discourse.julialang.org/t/base-kwdef-breaks-in-tests-only/91356/1 "2022-12-07T10:37:48Z")

</div>

**Julia v1.7.3**

I have encountered a problem with using `Base.@kwdef` that only occurs in tests, not when code is executed normally. An example:

File src/Example.jl:

```julia
module Example

Base.@kwdef mutable struct Foo
    bar :: Integer
end

Foo() = Foo(bar=1)

instance = Foo()
print("Instance value is $(instance.bar)")

end

```

Running this code with `julia src/Example.jl` results in the expected output: `Instance value is 1`

Now let’s add a test covering the constructor that takes no argument:

In file test/runtests.jl

```julia
using Test
using Example

@testset "default_foo_constructor" begin
    instance = Example.Foo()

    @test typeof(instance) == Example.Foo
    @test instance.bar == 1
end

```

Running the tests results in an error:

```nohighlight
     Testing Example
      Status `userdir\AppData\Local\Temp\jl_ADLTZW\Project.toml`
  [53506a2b] Example v0.1.0 `userdir\Projects\test-julia`
  [8dfed614] Test `@stdlib/Test`
      Status `userdir\AppData\Local\Temp\jl_ADLTZW\Manifest.toml`
  [53506a2b] Example v0.1.0 `userdir\Projects\test-julia`
  [2a0f44e3] Base64 `@stdlib/Base64`
  [b77e0a4c] InteractiveUtils `@stdlib/InteractiveUtils`
  [56ddb016] Logging `@stdlib/Logging`
  [d6f4376e] Markdown `@stdlib/Markdown`
  [9a3f8284] Random `@stdlib/Random`
  [ea8e919c] SHA `@stdlib/SHA`
  [9e88b42a] Serialization `@stdlib/Serialization`
  [8dfed614] Test `@stdlib/Test`
     Testing Running tests...
default_foo_constructor: Error During Test at projectdir\test\runtests.jl:4
  Got exception outside of a @test
  UndefKeywordError: keyword argument bar not assigned
  Stacktrace:
   [1] Example.Foo()
     @ Example .\util.jl:478
   [2] macro expansion
     @ projectdir\test\runtests.jl:5 [inlined]
   [3] macro expansion
     @ userdir\AppData\Local\Programs\Julia-1.7.3\share\julia\stdlib\v1.7\Test\src\Test.jl:1283 [inlined]
   [4] top-level scope
     @ projectdir\test\runtests.jl:5
   [5] include(fname::String)
     @ Base.MainInclude .\client.jl:451
   [6] top-level scope
     @ none:6
   [7] eval
     @ .\boot.jl:373 [inlined]
   [8] exec_options(opts::Base.JLOptions)
     @ Base .\client.jl:268
   [9] _start()
     @ Base .\client.jl:495
Test Summary: | Error Total
default_foo_constructor | 1 1
ERROR: LoadError: Some tests did not pass: 0 passed, 0 failed, 1 errored, 0 broken.
in expression starting at projectdir\test\runtests.jl:4
ERROR: Package Example errored during testing

```

This example is not exactly how we use `Base.@kwdef` in our project, but I was able to condense the problem down to this example. I’m just a bit confused why this error occurs. Perhaps I’m misunderstanding how constructors in general and `Base.@kwdef` in particular work, as I do find the concepts involved a bit confusing. We could also fairly easily not use the macro in the first place. It seems a useful tool for developers, but perhaps it would best not to mix keyword and positional constructors.

---

<div class="post-metadata">

### Author: ![Liozou](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/liozou/32/35118_2.png) [@Liozou](https://discourse.julialang.org/u/Liozou)
#### Post date: [December 7, 2022, 1:06pm UTC](https://discourse.julialang.org/t/base-kwdef-breaks-in-tests-only/91356/2 "2022-12-07T13:06:53Z")

</div>

I believe that’s unfortunately a case of this known issue: [https://github.com/JuliaLang/julia/issues/9498](https://github.com/JuliaLang/julia/issues/9498)  
Basically the issue is that if you define

```julia
foo(; bar) = bar
foo() = 1

```

then you will get the expected

```julia
julia> foo()
1

```

However, if you try to reverse the order of definitions in a new julia session:

```julia
foo() = 1
foo(; bar) = bar

```

then you get

```julia
julia> foo()
ERROR: UndefKeywordError: keyword argument bar not assigned

```

In particular, in your program, the order of method definitions for `Foo` is well-defined, but I don’t think there is any guarantee that the order is preserved post-precompilation, which likely results in the issue you observe when `test`ing it: the `Foo() = Foo(bar=1)` method gets virtually defined before the main constructor for `Foo`, which “shadows” it, if that makes sense.  
What makes me think precompilation is the issue is that adding a ` __precompile__ (false)` statement at the beginning of your module definition removes the error as well, but this statement is not meant to solve this kind of issue at all so I would recommend against using it.

What I can recommend instead is simply adding the default value for `bar` in your constructor:

```julia
module Example

Base.@kwdef mutable struct Foo
    bar::Integer=1 # notice the =1
end

instance = Foo()
print("Instance value is $(instance.bar)")

end

```

Isn’t this the behavior what you were looking for? Otherwise, I’m afraid the simplest solution is getting rid of the `Base.@kwdef` and just create one big constructor method taking the relevant keyword arguments and setting the default “by hand”…

---

<div class="post-metadata">

### Author: ![eott-siz](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/eott-siz/32/44936_2.png) [@eott-siz](https://discourse.julialang.org/u/eott-siz)
#### Post date: [December 7, 2022, 3:13pm UTC](https://discourse.julialang.org/t/base-kwdef-breaks-in-tests-only/91356/3 "2022-12-07T15:13:42Z")

</div>

Thanks for the reply, it has already helped with our problems. I haven’t fully groked the linked issue yet, but your explanation of the methods getting out of order and shadowing does make sense to me.

Regarding the modified example, that does indeed solve the problem… in the example. The use in our project is more complicated with multiple “non-default” constructor methods, mixed use of defaultable and non-defaultable fields, etc. However I’m confident I can find a solution, especially given that the keyword constructor method generated by `Base.@kwdef` is mostly convenience for our use case and nothing essential. I’ll consider the problem solved.
