集成测试#
在 conda
中的集成测试从较高层级测试应用程序,其中每个测试都可能涵盖代码的大部分。这些测试也可能使用本地文件系统和/或执行网络调用。在以下部分,我们将介绍一些关于这些测试如何运作的具体示例。当你编写自己的集成测试时,这些例子可以作为良好的起点。
conda_cli
固定装置:运行 CLI 级别测试#
CLI 级别测试是你能编写的最高级别的集成测试。这意味着测试中的代码以你在命令行中运行的方式执行。例如,你可能希望编写一个测试来确认在成功运行 conda create
后创建了一个环境。这样的测试看起来像这样
1import json
2from pathlib import Path
3
4from conda.testing import CondaCLIFixture
5
6
7def test_conda_create(conda_cli: CondaCLIFixture, tmp_path: Path):
8 # setup, create environment
9 out, err, code = conda_cli("create", "--prefix", tmp_path, "--yes")
10
11 assert f"conda activate {tmp_path}" in out
12 assert not err # no errors
13 assert not code # success!
14
15 # verify everything worked using the `conda env list` command
16 out, err, code = conda_cli("env", "list", "--json")
17
18 assert any(
19 tmp_path.samefile(path)
20 for path in json.loads(out).get("envs", [])
21 )
22 assert not err # no errors
23 assert not code # success!
24
25 # cleanup, remove environment
26 out, err, code = conda_cli("remove", "--all", "--prefix", tmp_path)
27
28 assert out
29 assert not err # no errors
30 assert not code # success!
让我们分解上面代码片段中究竟发生了什么
首先,我们依赖于一个固定装置(conda_cli
),它允许我们使用当前正在运行的进程来运行命令。这比通过子进程运行 CLI 测试效率更高、速度更快。
在测试本身中,我们首先通过实际运行 conda create
来创建一个新的环境。此函数返回命令的标准输出、标准错误和退出代码。这使我们能够进行检查,以确定命令是否成功运行。
测试的第二部分再次使用 conda_cli
固定装置来调用 conda env list
。这一次,我们传递了 --json
标志,它允许捕获 JSON,我们可以更好地解析并更容易地检查。然后我们断言我们刚刚创建的环境是否确实在可用的环境列表中。
最后,我们销毁了刚刚创建的环境,并确保标准错误和退出代码是我们期望的。
警告
在测试运行后,最好在可能的情况下使用临时目录(例如 tmp_path
)进行自动清理。否则,请记住删除测试期间创建的任何内容,因为这些内容将在其他测试运行时存在,并且可能导致意外的竞争条件。
tmp_env
固定装置:创建临时环境#
tmp_env
固定装置是为测试创建临时环境的便捷方法
1from conda.testing import CondaCLIFixture, TmpEnvFixture
2
3
4def test_environment_with_numpy(
5 tmp_env: TmpEnvFixture,
6 conda_cli: CondaCLIFixture,
7):
8 with tmp_env("numpy") as prefix:
9 out, err, code = conda_cli("list", "--prefix", prefix)
10
11 assert out
12 assert not err # no error
13 assert not code # success!
path_factory
固定装置:创建唯一(不存在)的路径#
path_factory
固定装置扩展了 pytest 的 tmp_path 固定装置,以提供唯一、未使用的路径。这使得在测试中更容易生成新的路径
1from conda.testing import (
2 CondaCLIFixture,
3 PathFactoryFixture,
4 TmpEnvFixture,
5)
6
7
8def test_conda_rename(
9 path_factory: PathFactoryFixture,
10 tmp_env: TmpEnvFixture,
11 conda_cli: CondaCLIFixture,
12 tmp_path: Path,
13):
14 # each call to `path_factory` returns a unique path
15 assert path_factory() != path_factory()
16
17 # each call to `path_factory` returns a path that is a child of `tmp_path`
18 assert path_factory().parent == path_factory().parent == tmp_path
19
20 with tmp_env() as prefix:
21 out, err, code = conda_cli("rename", "--prefix", prefix, path_factory())
22
23 assert out
24 assert not err # no error
25 assert not code # success!
使用固定装置的测试#
有时在集成测试中,你可能希望多次重复使用相同类型的环境。将此设置和拆卸代码复制粘贴到每个单独的测试中会使这些测试更难阅读,也更难维护。
为了克服这个问题,conda
测试广泛使用 pytest
固定装置。下面是之前显示的测试示例,只是我们现在将测试的重点放在 conda env list
命令上,并将环境的创建和删除移到一个固定装置中
1import json
2from pathlib import Path
3
4from conda.testing import CondaCLIFixture
5
6
7@pytest.fixture
8def env_one(tmp_env: TmpEnvFixture) -> Path:
9 with tmp_env() as prefix:
10 yield prefix
11
12
13def test_conda_create(env_one: Path, conda_cli: CondaCLIFixture):
14 # verify everything worked using the `conda env list` command
15 out, err, code = conda_cli("env", "list", "--json")
16
17 assert any(
18 env_one.samefile(path)
19 for path in json.loads(out).get("envs", [])
20 )
21 assert not err # no errors
22 assert not code # success!
在名为 env_one
的固定装置中,我们使用 tmp_env
固定装置创建一个新环境。我们使用 `yield` 来标记设置的结束。由于 tmp_env
固定装置扩展了 tmp_path
,因此不需要额外的拆卸。
此固定装置将使用 pytest
中的默认范围运行,该范围是 function
。这意味着设置和拆卸将在请求此固定装置的每个测试之前和之后发生。如果您需要在测试之间共享环境或其他数据,请记住适当地设置固定装置范围。在此处阅读有关 pytest
固定装置范围的更多信息。