Setup for Module/Package Testing

I’m developing a private package and I’m curious what the recommend process is. I started with the idea of using Pkg.develop(path=“path to my package”) but I’ve noticed that with this method I often need to restart the REPL because Revise is unable to revise the package in memory. With changes to the package and restarting the REPL I then get a package pre-compilation which takes some time. Therefore in development, specially in early stages, I’m wasting a lot of time in pre-compilation.

Another idea then is to not use Pkg.develop() but instead just use include(“path to my main module”). Then in my test script I use the following (name of main module being AM2App)

if !haskey(Pkg.installed(),"AM2App")
    include("../src/AM2App.jl")
    using .AM2App
else
    using AM2App
end
using Test

In development mode using the include(“module path”) seems to be a much faster because I can skip the pre-compilation step. Also the Module is easily replaced each time I run which means I don’t need to restart the REPL.

Am I going down the right path here?

Rather than trying to develop the package in your global package environment, you can instead activate the package’s own environment. That has a few advantages:

  • No need to modify your global package environment at all
  • Less potential confusion about what dependencies you are using (whatever is in your package’s Project.toml will be used)
  • Any packages you install during development will automatically be added to your package’s Project.toml and Manifest.toml, making it easy to reproduce your state later.

Activating your package’s environment just requires that you Pkg.activate("/path/to/your/package/folder") or cd into that folder and do julia --project. I’ve also found Revise to be pretty reliable in this setup. The only thing it can’t do is manage changing type definitions, which is indeed unfortunate. I usually just restart Julia in that case (or restart my Jupyter kernel) which I agree is rather annoyingly slow sometimes.

5 Likes

Thanks, that’s a good point about the dependencies.

This method still requires package pre-compilation though, right?

Also, is it possible to somehow check which active environment Julia is using? My if block using !haskey(Pkg.installed(),“AM2App”) no longer works when I run in project mode. It would be cool if I could write my test scripts so they can work in Project mode or in include() mode.

Base.active_project() will give you the path to the Project.toml Pkg is currently using.

Pkg.installed(), which I think is now being deprecated, do not returns the project package as installed.

Well, if your tests are located in the default test/runtests.jl file you should be able to just do:

# test/runtests.jl
using MyPackage
using Test

# My tests ...

If you run the tests using Pkg.test("MyPackage") it will run the test in “project mode”, always using the version of MyPackage that the current active project refers to.

What I’ve found is working best for me is to have a run.jl and runtests.jl files in my test folder.

TestApp
   src
      TestApp.jl
   test
       run.jl
       runtests.jl
       runtests_test1.jl
       runtests_test2.jl

Then I break up my actual testing into files like runtests_test1.jl, runtests_test2.jl, etc.

For runtests.jl I have

using TestApp

include("runtests_test1.jl")
include("runtests_test2.jl")

And for run.jl I have

include("../src/TestApp.jl")
using .TestApp

# include("runtests_test1.jl") #skip this test for now...
include("runtests_test2.jl") 

The advantages are:

  1. I can quickly execute run.jl and I don’t need to wait for pre-compilation. The module is simply replaced in Main and I can quickly develop new functions and sort out simple bugs

  2. I can toggle which tests I want to run by simply commenting out include statements

  3. When I’m ready to test the full package or generate coverage info I can run Pkg.test() to run the same test scripts properly

  4. I can generate trace-compile statements for PackageCompiler using:

    • julia --startup-file=no --trace-compile=precompiles.jl TestApp/test/run.jl

    Whereas I have found the following does not work, even though it executes the same test scripts

    • julia --project=TestApp --startup-file=no --trace-compile=precompiles.jl -e "using Pkg; Pkg.test()"
1 Like

This puts Revise into Project.toml, but my package doesn’t really depend on it. Is it possible to not make my package depend on Revise, but still use it during development?

EDIT: one way seems to be to use test-specific dependencies

Yeah, you just need to install Revise in your global package environment. You do that by starting Julia (without a --project argument) and then doing ]add Revise.

1 Like