Rulle
Rulle

Reputation: 4901

Inheriting dependencies when running unit tests from command line

I am trying to run Julia unit tests from the command line but the unit tests fail to run because they cannot find a dependency that I am using in my main project. How can I make this work? The actual command that I try to execute is julia test/test_blueprint.jl from the project root. Here follows more details.

Details about the setup

My project is located at the path /home/jonas/prog/julia/blueprint. In that directory, I have a Project.toml file containing these lines:

name = "blueprint"
uuid = "c1615a0c-c255-402d-ae34-0b88819b43c6"
authors = [""]
version = "0.1.0"

[deps]
FunctionalCollections = "de31a74c-ac4f-5751-b3fd-e18cd04993ca"
Setfield = "efcf1570-3423-57d1-acb7-fd33fddbac46"

along with the Manifest.toml file.

I have a subdirectory at test/ with unit tests that I created following this guide and that directory contains another Project.toml file containing

[deps]
Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"

There is a file test/test_blueprint.jl with unit tests and that file starts with

using Test
include("../src/blueprint.jl") # Alternative 1
#using blueprint               # Alternative 2
using FunctionalCollections
using LinearAlgebra
...

The actual code being tested is in the file src/blueprint.jl.

Details about the problem

From the project root, I attempt to run the unit tests using the command julia test/test_blueprint.jl. When I run that command it produces the following output:

ERROR: LoadError: ArgumentError: Package Setfield not found in current path:
- Run `import Pkg; Pkg.add("Setfield")` to install the Setfield package.

Stacktrace:
 [1] require(into::Module, mod::Symbol)
   @ Base ./loading.jl:967
 [2] include(fname::String)
   @ Base.MainInclude ./client.jl:451
 [3] top-level scope
   @ ~/prog/julia/blueprint/test/test_blueprint.jl:8
in expression starting at /home/jonas/prog/julia/blueprint/src/blueprint.jl:1
in expression starting at /home/jonas/prog/julia/blueprint/test/test_blueprint.jl:8

suggesting that it cannot find the dependency Setfield. If I edit the top of the file test/test_blueprint.jl slightly from

include("../src/blueprint.jl") # Alternative 1
#using blueprint               # Alternative 2

to

#include("../src/blueprint.jl") # Alternative 1
using blueprint                 # Alternative 2

it still fails, but with a different error:

ERROR: LoadError: ArgumentError: Package blueprint not found in current path:
- Run `import Pkg; Pkg.add("blueprint")` to install the blueprint package.

Stacktrace:
 [1] require(into::Module, mod::Symbol)
   @ Base ./loading.jl:967
in expression starting at /home/jonas/prog/julia/blueprint/test/test_blueprint.jl:9

Question: How can I make the unit tests run from the command line?

Note that I can run the unit tests from within the Julia REPL in Emacs by activating the project using C-c C-a at the src/blueprint.jl file and calling C-c C-b at the unit test file test/test_blueprint.jl. My Julia version is 1.7.0 (2021-11-30). Don't hesitate to ask for more clarifications.

Upvotes: 4

Views: 569

Answers (2)

cbk
cbk

Reputation: 4370

First, a few naming conventions that are probably not (but may be) contributing to the issues here:

  • By convention, package names begin with a single capital, so I would recommend changing the name to Blueprint everywhere
  • By default, ] test runs tests found in the test/runtests.jl, so I would recommend naming your top-level testing script runtests.jl to avoid confusion, even though it does seem from the errors here that test is finding your test_blueprint.jl file one way or another.

Now, while I can't test this without the full code of your package, what I suspect is happening here is the following:

  • Normally, dependencies of the package you are testing (let's say MyPackage) are not required in test/Project.toml because they are implicit in MyPackage. So after a successful using MyPackage, while they will still not be available to any functions written in your test scripts (test/runtests.jl), will be available to the functions written in MyPackage -- just as if you had typed ]using MyPackage at the REPL and then run your test code there. This is the only reason you don't normally need to duplicate all the deps from the main Project.toml in test/Project.toml.
  • Since the using Blueprint approach is failing here for other reasons, when you simply include the code from src/blueprint.jl, the usings within that file will in turn fail because those packages are not present in the active environment at test/Project.toml (even if they are present on your system elsewhere).
  • Consequently, one quick fix to your problem with the current include("../src/blueprint.jl") approach would be to simply add those dependencies to your test/Project.toml

However, it would be more satisfying to fix the problem you are having with using Blueprint. I don't have enough information to debug this without seeing the full structure of your packages, but I would suggest as a start

  • making sure that your code is properly structured as a package
  • testing that, even if unregistered, you can ] add your package from the REPL by git repo URL (i.e. ] add https://some_website.com/you/Blueprint.jl)

EDIT: Upon inspection of the code linked in the comments (https://github.com/jonasseglare/Blueprint), a few other issues:

  • Although they are already installed by default, standard libraries these days do need to be included in [deps]. In this case, that means the LinearAlgebra stdlib
  • Any packages you are explicitly using in your test scripts, other than your package itself, do need to be added to test/Project.toml. I.e., any packages that you are directly using functions from in your test scripts (rather than just indirectly using via the exported functions of your package) do need to be included in test/Project.toml. In your case, the latter would appear to mean LinearAlgebra and FunctionalCollections, but not Setfield (that one only needs to be included in the regular Project.toml, since it's not being directly used in runtests.jl).

Consequently, with a few minor changes to your repo we are able to simply

] add https://github.com/brenhinkeller/Blueprint
] test Blueprint

or, since you preferred at the command line

user$ julia -e "using Pkg; Pkg.add(url=\"https://github.com/brenhinkeller/Blueprint\")
user$ julia -e "using Pkg; Pkg.test(\"Blueprint\")"
     Testing Blueprint
      Status `/private/var/folders/qk/2qyrdb854mvd2tn4crc802lw0000gn/T/jl_fSypP7/Project.toml`
  [c1615a0c] Blueprint v0.1.0 `https://github.com/brenhinkeller/Blueprint#master`
  [de31a74c] FunctionalCollections v0.5.0
  [37e2e46d] LinearAlgebra `@stdlib/LinearAlgebra`
  [8dfed614] Test `@stdlib/Test`
      Status `/private/var/folders/qk/2qyrdb854mvd2tn4crc802lw0000gn/T/jl_fSypP7/Manifest.toml`
  [c1615a0c] Blueprint v0.1.0 `https://github.com/brenhinkeller/Blueprint#master`
  [187b0558] ConstructionBase v1.3.0
  [de31a74c] FunctionalCollections v0.5.0
  [1914dd2f] MacroTools v0.5.9
  [ae029012] Requires v1.3.0
  [efcf1570] Setfield v0.8.1
  [56f22d72] Artifacts `@stdlib/Artifacts`
  [2a0f44e3] Base64 `@stdlib/Base64`
  [9fa8497b] Future `@stdlib/Future`
  [b77e0a4c] InteractiveUtils `@stdlib/InteractiveUtils`
  [8f399da3] Libdl `@stdlib/Libdl`
  [37e2e46d] LinearAlgebra `@stdlib/LinearAlgebra`
  [56ddb016] Logging `@stdlib/Logging`
  [d6f4376e] Markdown `@stdlib/Markdown`
  [9a3f8284] Random `@stdlib/Random`
  [ea8e919c] SHA `@stdlib/SHA`
  [9e88b42a] Serialization `@stdlib/Serialization`
  [8dfed614] Test `@stdlib/Test`
  [cf7118a7] UUIDs `@stdlib/UUIDs`
  [e66e0078] CompilerSupportLibraries_jll `@stdlib/CompilerSupportLibraries_jll`
  [4536629a] OpenBLAS_jll `@stdlib/OpenBLAS_jll`
  [8e850b90] libblastrampoline_jll `@stdlib/libblastrampoline_jll`
     Testing Running tests...
Test Summary: | Pass  Total
Plane tests   |    7      7
Test Summary:      | Pass  Total
Plane intersection |    2      2
Test Summary:        | Pass  Total
Plane intersection 2 |    4      4
Test Summary:   | Pass  Total
Plane shadowing |    3      3
Test Summary:    | Pass  Total
Polyhedron tests |    3      3
Test Summary:      | Pass  Total
Polyhedron tests 2 |    5      5
Test Summary: | Pass  Total
Beam tests    |    2      2
Test Summary:   | Pass  Total
Half-space test |    2      2
Test Summary:     | Pass  Total
Ordered pair test |    2      2
Test Summary:                | Pass  Total
Test plane/line intersection |    2      2
Test Summary:           | Pass  Total
Update line bounds test |   21     21
     Testing Blueprint tests passed

FWIW, you should also be able to mix and match those command-line and REPL approaches (i.e., install in repl, test via command line or vice versa).

While I had not originally considered this case, one additional possibility discussed in the comments is where one wishes to test the local state of a package without, or without relying upon, a git remote; in this case @Rulle reports that activating the package directory, i.e,

julia -e "using Pkg; Pkg.activate(\".\"); Pkg.test(\"Blueprint\")" 

or

julia --project=. -e "using Pkg; Pkg.test(\"Blueprint\")"

or equivalently in the REPL

] activate .
] test Blueprint

will work assuming the package directory is currently the local directory .

Upvotes: 1

Rulle
Rulle

Reputation: 4901

Possible answer to my own question:

To make it work, specify the main project root directory on the command line when calling the script using --project. In this case, we would call

julia --project=/home/jonas/prog/julia/blueprint test/test_blueprint.jl

However, there seems to be some hidden state that I don't understand, because after this command has been run once, it seems as if the --project option can be omitted. On the other hand, I have also tried to provide a nonsense project directory, e.g. /tmp:

julia --project=/tmp test/test_blueprint.jl

and sometimes it will still run the unit tests (!) and sometimes it won't. But when it fails to run the unit tests, it will succeed again as soon as I specify the correct path, that is /home/jonas/prog/julia/blueprint. I don't understand also how this interacts with whether I use using blueprint or include('../src/blueprint.jl') but it seems as if, when I use using, it works only iff the --project path is set correctly. But I am still not sure.

Upvotes: 1

Related Questions