运行 从命令行进行单元测试时继承依赖关系

Inheriting dependencies when running unit tests from command line

我正在尝试从命令行 运行 Julia 单元测试,但单元测试失败 运行 因为它们找不到我在主项目中使用的依赖项。我怎样才能使这项工作?我尝试执行的实际命令是来自项目根目录的 julia test/test_blueprint.jl 。下面是更多详细信息。

有关设置的详细信息

我的项目位于路径/home/jonas/prog/julia/blueprint。在该目录中,我有一个包含这些行的 Project.toml 文件:

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"

连同 Manifest.toml 文件。

我在 test/ 有一个子目录,其中包含我在 this guide 之后创建的单元测试,该目录包含另一个 Project.toml 文件,其中包含

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

有一个包含单元测试的文件 test/test_blueprint.jl,该文件以

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

正在测试的实际代码在文件 src/blueprint.jl.

问题详情

从项目根目录,我尝试 运行 使用命令 julia test/test_blueprint.jl 进行单元测试。当我 运行 该命令时,它会产生以下输出:

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

提示找不到依赖项Setfield。如果我从

稍微编辑文件的顶部 test/test_blueprint.jl
include("../src/blueprint.jl") # Alternative 1
#using blueprint               # Alternative 2

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

它仍然失败,但出现不同的错误:

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

问题:如何从命令行进行单元测试运行?

请注意,我 可以 运行 通过使用 C-c C-asrc/blueprint.jl 文件并在单元测试文件 test/test_blueprint.jl 中调用 C-c C-b。我的 Julia 版本是 1.7.0 (2021-11-30)。不要犹豫,要求更多说明。

首先,一些可能不会(但可能会)导致此处问题的命名约定:

  • 按照惯例,包名称以单个大写字母开头,因此我建议将名称更改为 Blueprint 无处不在
  • 默认情况下,] test 运行s 测试在 test/runtests.jl 中找到,所以我建议将您的顶级测试脚本命名为 runtests.jl 以避免混淆,即使尽管从此处的错误来看 test 确实以某种方式找到您的 test_blueprint.jl 文件。

现在,虽然我无法在没有您的软件包的完整代码的情况下进行测试,但我怀疑这里发生的情况如下:

  • 通常,test/Project.toml 中不需要您正在测试的包的依赖项(比方说 MyPackage),因为它们在 MyPackage 中是隐式的。因此,在成功 using MyPackage 之后,虽然它们仍然无法用于在您的测试脚本 中编写的任何函数 (test/runtests.jl),但 可用于 MyPackage 中编写的函数——就像您在 REPL 中键入 ]using MyPackage 然后 运行 您的测试代码一样。这是您通常不需要从 test/Project.toml.
  • 中的主要 Project.toml 复制所有部门的唯一原因
  • 由于 using Blueprint 方法由于其他原因在这里失败,当您简单地 include 来自 src/blueprint.jl 的代码时,该文件中的 using 将依次失败,因为这些软件包不存在于 test/Project.toml 的活动环境中(即使它们存在于您的系统其他地方)。
  • 因此,使用当前 include("../src/blueprint.jl") 方法快速解决问题的一种方法是将这些依赖项简单地添加到 test/Project.toml

但是,解决您在 using Blueprint 中遇到的问题会更令人满意。在没有看到你的包的完整结构的情况下,我没有足够的信息来调试它,但我建议作为一个开始

  • 确保您的代码是 properly structured as a package
  • 测试即使未注册,您也可以通过 git repo URL(即 ] add https://some_website.com/you/Blueprint.jl
  • 从 REPL ] add 您的包裹

编辑: 检查评论中链接的代码 (https://github.com/jonasseglare/Blueprint),发现其他一些问题:

  • 虽然它们已经默认安装,但现在的标准库确实需要包含在 [deps] 中。在这种情况下,这意味着 LinearAlgebra stdlib
  • 您在测试脚本中明确 using 的任何包,除了您的包本身,do 需要添加到 test/Project.toml。即,任何您在测试脚本中 直接 using 运行的包(而不是通过包的导出函数间接使用)都需要包含在 test/Project.toml。 在你的情况下,后者似乎意味着 LinearAlgebraFunctionalCollections,但不是 Setfield(那个只需要包含在常规 Project.toml 中,因为它不是直接用在runtests.jl).

因此,通过一些 minor changes to your repo 我们可以简单地

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

或者,因为您更喜欢使用命令行

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,您还应该能够混合和匹配那些命令行和 REPL 方法(即,在 repl 中安装,通过命令行测试,反之亦然)。

虽然我最初没有考虑过这种情况,但评论中讨论的另一种可能性是希望在没有或不依赖 git 远程的情况下测试包的本地状态;在这种情况下,@Rulle 报告激活包目录,即

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

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

或 REPL 中的等价物

] activate .
] test Blueprint

假设包目录当前是本地目录.

我自己的问题的可能答案:

要使其正常运行,请在使用 --project 调用脚本时在命令行中指定主项目根目录。在这种情况下,我们会调用

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

不过好像有什么隐藏状态我不太明白,因为这个命令运行一次后,好像--project这个选项可以省略了。另一方面,我也试图提供一个废话项目目录,例如/tmp:

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

有时它仍会 运行 单元测试 (!) 有时不会。但是当它运行单元测试失败时,只要我指定正确的路径,它就会再次成功,即/home/jonas/prog/julia/blueprint。我也不明白这与我使用 using blueprint 还是 include('../src/blueprint.jl') 如何相互作用,但似乎当我使用 using 时,它只起作用 iff​​ --project 路径设置正确。但是我还是不确定。