Organizing Julia code

I understand that Julia projects conventionally have src and test directories. How does one connect the latter to the former? This works:

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

But perhaps there is a better way, involving some configuration file within the project?

Is there a convention for naming unit tests and integration tests? Can someone recommend a small package that I could use as a model?

Thanks

1 Like

Do you want a package or just a project? Check out 4. Working with Environments · Pkg.jl and if you’re after a package, then PkgTemplates.jl (GitHub - invenia/PkgTemplates.jl: Create new Julia packages, the easy way) are the way to go.

3 Likes

Usually one would be

using ThatModule

in the unit tests.

A tiny package that I like is

and may be useful as an example.

You may want to use a package template generator too, eg

3 Likes

As a starting point,
I typically mirror the folder structure of src in test.
So if i have files: src/foo.jl and src/bar.jl I will also have test/foo.jl and test/bar.jl.

then i might also add seperate files on top for integration testing,
or i might not.
Depending on the project

2 Likes

I’ve had a look at UnPack.jl and am still confused. Under UnPack.jl, the test directory has a file called runtests.jl, which begins with

using UnPack

When I execute that file (julia runtests.jl), I get

[Alans-MacBook-Air test]$ julia runtests.jl
ERROR: LoadError: ArgumentError: Package UnPack not found in current path:
- Run `import Pkg; Pkg.add("UnPack")` to install the UnPack package.

Stacktrace:
 [1] require(::Module, ::Symbol) at ./loading.jl:892
 [2] include(::Module, ::String) at ./Base.jl:377
 [3] exec_options(::Base.JLOptions) at ./client.jl:288
 [4] _start() at ./client.jl:484
 in expression starting at /Users/rogers/distrib/UnPack/test/runtests.jl:2

Clearly, the Project.toml file is not enough to tell Julia how to find the source code. Do I need to install or activate this package using the package manager? If I do that, how can I be sure I’m testing the local code (in …/src) rather than a version installed elsewhere by Pkg?

Thanks

Workflow is like this:

  1. Run ]activate .; instantiate in the package folder.
  2. Afterwards run ]test.
4 Likes

This works from within the REPL, but from the Unix shell,

julia runtest.jl

still bombs. Is this as expected?

Thanks for the help.

Yes. You can make a script to run the tests from what I posted.

using Pkg
Pkg.activate(".");
Pkg.instantiate()
Pkg.test()

Call it “mytest.jl” and run as julia mytest.jl.

2 Likes

Yes.

Also, most people use an interactive REPL for Julia, usually from some editor/IDE. If you want to run things from the command line, you will face the cost of compilation each time, so it will be frustrating way of using Julia.

1 Like

The manual section Code Loading · The Julia Language describes how name conflicts can occur when you use a private name that ends up being in the public space created by other popular packages.
I would suggest a useful convention is calling private modules MyData, MyTest etc, these modules would not have name conflicts and you wouldn’t have to carefully manage the coding loading environment.

One way is to use julia --project from your project’s root directory.

First I make a dummy project:

max@opt ~/sandbox> julia
               _
   _       _ _(_)_     |  Documentation: https://docs.julialang.org
  (_)     | (_) (_)    |
   _ _   _| |_  __ _   |  Type "?" for help, "]?" for Pkg help.
  | | | | | | |/ _` |  |
  | | |_| | | | (_| |  |  Version 1.8.0-beta1 (2022-02-23)
 _/ |\__'_|_|_|\__'_|  |  Official https://julialang.org/ release
|__/                   |

(@v1.8) pkg> generate MyNewJuliaProject
  Generating  project MyNewJuliaProject:
    MyNewJuliaProject/Project.toml
    MyNewJuliaProject/src/MyNewJuliaProject.jl

julia> exit()

Next I cd into the project and create some tests. Then do julia --project, add the Test package itself as a dependency (you only have to do this once), then run ]test which should automatically do all the tests in your runtests.jl:

max@opt ~/sandbox> cd MyNewJuliaProject/
max@opt ~/s/MyNewJuliaProject> mkdir test
max@opt ~/s/MyNewJuliaProject> echo "using Test; @test true" > test/runtests.jl
max@opt ~/s/MyNewJuliaProject> julia --project
               _
   _       _ _(_)_     |  Documentation: https://docs.julialang.org
  (_)     | (_) (_)    |
   _ _   _| |_  __ _   |  Type "?" for help, "]?" for Pkg help.
  | | | | | | |/ _` |  |
  | | |_| | | | (_| |  |  Version 1.8.0-beta1 (2022-02-23)
 _/ |\__'_|_|_|\__'_|  |  Official https://julialang.org/ release
|__/                   |

(MyNewJuliaProject) pkg> add Test
    Updating registry at `~/.julia/registries/General.toml`
   Resolving package versions...
    Updating `~/sandbox/MyNewJuliaProject/Project.toml`
  [8dfed614] + Test
    Updating `~/sandbox/MyNewJuliaProject/Manifest.toml`
  [2a0f44e3] + Base64
  [b77e0a4c] + InteractiveUtils
  [56ddb016] + Logging
  [d6f4376e] + Markdown
  [9a3f8284] + Random
  [ea8e919c] + SHA v0.7.0
  [9e88b42a] + Serialization
  [8dfed614] + Test

(MyNewJuliaProject) pkg> test
     Testing MyNewJuliaProject
      Status `/tmp/jl_6ouu8z/Project.toml`
  [a2f463a9] MyNewJuliaProject v0.1.0 `~/sandbox/MyNewJuliaProject`
  [8dfed614] Test `@stdlib/Test`
      Status `/tmp/jl_6ouu8z/Manifest.toml`
  [a2f463a9] MyNewJuliaProject v0.1.0 `~/sandbox/MyNewJuliaProject`
  [2a0f44e3] Base64 `@stdlib/Base64`
  [b77e0a4c] InteractiveUtils `@stdlib/InteractiveUtils`
  [56ddb016] Logging `@stdlib/Logging`
  [d6f4376e] Markdown `@stdlib/Markdown`
  [9a3f8284] Random `@stdlib/Random`
  [ea8e919c] SHA v0.7.0 `@stdlib/SHA`
  [9e88b42a] Serialization `@stdlib/Serialization`
  [8dfed614] Test `@stdlib/Test`
     Testing Running tests...
     Testing MyNewJuliaProject tests passed

(MyNewJuliaProject) pkg>

julia> exit()

Another way is to ]develop your package on your “main” Julia environment. This lets you use plain-old julia (without the --project flag) and you can use packages you have on your Julia environment without adding them as dependencies.

max@opt ~/s/MyNewJuliaProject> cd ~
max@opt ~> julia
               _
   _       _ _(_)_     |  Documentation: https://docs.julialang.org
  (_)     | (_) (_)    |
   _ _   _| |_  __ _   |  Type "?" for help, "]?" for Pkg help.
  | | | | | | |/ _` |  |
  | | |_| | | | (_| |  |  Version 1.8.0-beta1 (2022-02-23)
 _/ |\__'_|_|_|\__'_|  |  Official https://julialang.org/ release
|__/                   |

(@v1.8) pkg> develop /home/max/sandbox/MyNewJuliaProject/
   Resolving package versions...
    Updating `~/.julia/environments/v1.8/Project.toml`
  [a2f463a9] + MyNewJuliaProject v0.1.0 `~/sandbox/MyNewJuliaProject`
    Updating `~/.julia/environments/v1.8/Manifest.toml`
  [a2f463a9] + MyNewJuliaProject v0.1.0 `~/sandbox/MyNewJuliaProject`

(@v1.8) pkg> test MyNewJuliaProject
     Testing MyNewJuliaProject
      Status `/tmp/jl_C8tprf/Project.toml`
  [a2f463a9] MyNewJuliaProject v0.1.0 `~/sandbox/MyNewJuliaProject`
  [8dfed614] Test `@stdlib/Test`
      Status `/tmp/jl_C8tprf/Manifest.toml`
  [a2f463a9] MyNewJuliaProject v0.1.0 `~/sandbox/MyNewJuliaProject`
  [2a0f44e3] Base64 `@stdlib/Base64`
  [b77e0a4c] InteractiveUtils `@stdlib/InteractiveUtils`
  [56ddb016] Logging `@stdlib/Logging`
  [d6f4376e] Markdown `@stdlib/Markdown`
  [9a3f8284] Random `@stdlib/Random`
  [ea8e919c] SHA v0.7.0 `@stdlib/SHA`
  [9e88b42a] Serialization `@stdlib/Serialization`
  [8dfed614] Test `@stdlib/Test`
     Testing Running tests...
     Testing MyNewJuliaProject tests passed

(@v1.8) pkg>

Edit: Just realized how old this thread was. Hope this was helpful to someone anyhow.

I still cannot figure out how to use both versioned public packages, and my own unversioned modules in the same project. When I add a Project.toml file to my directory, I can no longer load my own modules, unless I create a package with UUID for every single module.
I looked at packaged like PyCall, PythonCall, DataFrames, they all have just one massive module and include a bunch of source files. They don’t even use the module feature to separate program logic, within their own project.