Skip to content

Commit 45528a9

Browse files
committed
DRY up the test code a bit.
Remove tmp_path fixture from every test, but then need to write a nested function for the fixture. Also add a DEFAULT_CONFIG for the cookiecutter generation.
1 parent f8c96c6 commit 45528a9

4 files changed

Lines changed: 99 additions & 107 deletions

File tree

tests/conftest.py

Lines changed: 9 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -6,34 +6,16 @@
66

77
import pytest
88

9-
10-
def _generate_package(
11-
config: dict[str, str], path: pathlib.Path
12-
) -> subprocess.CompletedProcess[str]:
13-
"""
14-
Generate a project from the cookiecutter template.
15-
16-
Arguments:
17-
---------
18-
config: dict
19-
A dictionary with values for the cookiecutter template,
20-
as defined in the cookiecutter.json
21-
path: Path
22-
Directory to create package in.
23-
24-
"""
25-
args = [f"{key}={val}" for key, val in config.items()]
26-
cmd = ["cookiecutter", ".", "--no-input", "--output-dir", f"{path}"]
27-
return subprocess.run( # noqa: S603
28-
cmd + args,
29-
check=False,
30-
shell=False,
31-
capture_output=True,
32-
text=True,
33-
)
9+
from .helpers import DEFAULT_CONFIG, _generate_package # type: ignore[import-not-found]
3410

3511

3612
@pytest.fixture
37-
def generate_package() -> typing.Callable:
13+
def generate_package(tmp_path: pathlib.Path) -> typing.Callable:
3814
"""Generate project from cookiecutter template."""
39-
return _generate_package
15+
16+
def wrapped_with_tmp_path(
17+
config: dict[str, str] = DEFAULT_CONFIG,
18+
) -> tuple[subprocess.CompletedProcess, pathlib.Path]:
19+
return _generate_package(config, tmp_path)
20+
21+
return wrapped_with_tmp_path

tests/helpers.py

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
"""Helper functions for the cookiecutter template tests."""
2+
3+
import os
4+
import pathlib
5+
import subprocess
6+
7+
DEFAULT_CONFIG = {
8+
"github_owner": "test-user",
9+
"project_short_description": "description",
10+
"project_name": "Cookiecutter Test",
11+
"project_slug": "cookiecutter-test",
12+
}
13+
14+
15+
def _generate_package(
16+
config: dict[str, str], path: pathlib.Path
17+
) -> tuple[subprocess.CompletedProcess[str], pathlib.Path]:
18+
"""
19+
Generate a project from the cookiecutter template.
20+
21+
Arguments:
22+
---------
23+
config: dict
24+
A dictionary with values for the cookiecutter template,
25+
as defined in the cookiecutter.json
26+
path: Path
27+
Directory to create package in.
28+
29+
Returns:
30+
-------
31+
subprocess.CompletedProcess, pathlib.Path
32+
The result of the cookiecutter command and the path to the generated package.
33+
34+
"""
35+
args = [f"{key}={val}" for key, val in config.items()]
36+
cmd = ["cookiecutter", ".", "--no-input", "--output-dir", f"{path}"]
37+
return subprocess.run( # noqa: S603
38+
cmd + args,
39+
check=False,
40+
shell=False,
41+
capture_output=True,
42+
text=True,
43+
), path / config["project_slug"]
44+
45+
46+
def get_all_files_folders(root_path: pathlib.Path) -> set[pathlib.Path]:
47+
"""
48+
Get all files and folders under a directory.
49+
50+
The paths are returned relative to the root path given.
51+
__pycache__ directories and .DS_Store files are ignored.
52+
"""
53+
file_set: set[pathlib.Path] = set()
54+
for dirpath, _, filenames in os.walk(root_path):
55+
dirpath_path = pathlib.Path(dirpath).relative_to(root_path)
56+
if dirpath_path.name in ["__pycache__"]:
57+
continue
58+
59+
# Add this directory
60+
file_set.update((dirpath_path,))
61+
# Add any files in it
62+
for filename in filenames:
63+
if filename in [".DS_Store"]:
64+
continue
65+
file_set.update((dirpath_path / filename,))
66+
67+
return file_set

tests/test_git_init.py

Lines changed: 5 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,23 @@
11
"""Checks that the git repo initialisation works."""
22

3-
import pathlib
43
import subprocess
54
import typing
65

76
import pytest
87

8+
from .helpers import DEFAULT_CONFIG # type: ignore[import-not-found]
9+
910

1011
@pytest.mark.parametrize("initialise_git_repository", [True, False])
1112
def test_initialisation_of_git_repo(
1213
initialise_git_repository: bool, # noqa: FBT001
1314
generate_package: typing.Callable,
14-
tmp_path: pathlib.Path,
1515
) -> None:
1616
"""Checks to see if git was correctly initialised if desired."""
17-
test_config = {
18-
"github_owner": "test-user",
19-
"project_short_description": "description",
20-
"project_name": "Cookiecutter Test",
21-
"initialise_git_repository": initialise_git_repository,
22-
}
17+
test_config = DEFAULT_CONFIG.copy()
18+
test_config["initialise_git_repository"] = str(initialise_git_repository)
2319
# Run cookiecutter with initialise_git_repository
24-
result = generate_package(config=test_config, path=tmp_path)
25-
26-
test_project_dir = tmp_path / "cookiecutter-test"
20+
result, test_project_dir = generate_package(config=test_config)
2721

2822
# check if git is initialised
2923
git_status = subprocess.run( # noqa: S603

tests/test_package_generation.py

Lines changed: 18 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
"""Checks that the cookiecutter works."""
22

33
import difflib
4-
import os
54
import pathlib
65
import shutil
76
import subprocess
@@ -10,52 +9,24 @@
109
import pytest
1110
import pytest_venv # type: ignore[import-not-found]
1211

12+
from .helpers import ( # type: ignore[import-not-found]
13+
DEFAULT_CONFIG,
14+
get_all_files_folders,
15+
)
1316

14-
def get_all_files_folders(root_path: pathlib.Path) -> set[pathlib.Path]:
15-
"""
16-
Get all files and folders under a directory.
1717

18-
The paths are returned relative to the root path given.
19-
__pycache__ directories and .DS_Store files are ignored.
20-
"""
21-
file_set: set[pathlib.Path] = set()
22-
for dirpath, _, filenames in os.walk(root_path):
23-
dirpath_path = pathlib.Path(dirpath).relative_to(root_path)
24-
if dirpath_path.name in ["__pycache__"]:
25-
continue
26-
27-
# Add this directory
28-
file_set.update((dirpath_path,))
29-
# Add any files in it
30-
for filename in filenames:
31-
if filename in [".DS_Store"]:
32-
continue
33-
file_set.update((dirpath_path / filename,))
34-
35-
return file_set
36-
37-
38-
def test_package_generation(
39-
tmp_path: pathlib.Path,
40-
generate_package: typing.Callable,
41-
) -> None:
18+
def test_package_generation(generate_package: typing.Callable) -> None:
4219
"""Test package generation."""
43-
test_config = {
44-
"github_owner": "test-user",
45-
"project_short_description": "description",
46-
"project_name": "Cookiecutter Test",
47-
# Not having a git repo makes it easier to check in/out reference
48-
# data files to the main python-tooling git repository
49-
"initialise_git_repository": False,
50-
}
51-
generate_package(config=test_config, path=tmp_path)
20+
test_config = DEFAULT_CONFIG.copy()
21+
# Not having a git repo makes it easier to check in/out reference
22+
# data files to the main python-tooling git repository
23+
test_config["initialise_git_repository"] = "False"
24+
_, test_project_dir = generate_package(config=test_config)
5225

5326
expected_package_dir = (
5427
pathlib.Path(__file__).parent / "data" / "test_package_generation"
5528
)
56-
# Check project directory exists
57-
test_project_dir = tmp_path / "cookiecutter-test"
58-
assert test_project_dir.exists()
29+
assert test_project_dir.exists(), "Project directory does not exist."
5930

6031
actual_files = get_all_files_folders(test_project_dir)
6132
expected_files = get_all_files_folders(expected_package_dir)
@@ -94,18 +65,11 @@ def test_package_generation(
9465

9566

9667
def test_pip_installable(
97-
tmp_path: pathlib.Path,
9868
venv: pytest_venv.VirtualEnvironment,
9969
generate_package: typing.Callable,
10070
) -> None:
10171
"""Test generated package is pip installable."""
102-
test_config = {
103-
"github_owner": "test-user",
104-
"project_short_description": "description",
105-
"project_name": "Cookiecutter Test",
106-
}
107-
generate_package(config=test_config, path=tmp_path)
108-
test_project_dir = tmp_path / "cookiecutter-test"
72+
_, test_project_dir = generate_package()
10973
# Try to install package in virtual environment with pip
11074
pipinstall = subprocess.run( # noqa: S603
11175
[
@@ -124,21 +88,13 @@ def test_pip_installable(
12488
)
12589

12690

127-
@pytest.mark.parametrize("funder", ["", "STFC"])
128-
def test_optional_funder(
129-
tmp_path: pathlib.Path, generate_package: typing.Callable, funder: str
130-
) -> None:
91+
@pytest.mark.parametrize("funder", ["", "STFC", "UKRI", "Wellcome Trust"])
92+
def test_optional_funder(generate_package: typing.Callable, funder: str) -> None:
13193
"""Test specifying funder or not in package generation."""
132-
config = {
133-
"github_owner": "test-user",
134-
"project_short_description": "description",
135-
"project_name": "Cookiecutter Test",
136-
"funder": funder,
137-
}
138-
139-
generate_package(config, tmp_path)
94+
config = DEFAULT_CONFIG.copy()
95+
config["funder"] = funder
96+
_, test_project_dir = generate_package(config)
14097

141-
test_project_dir = tmp_path / "cookiecutter-test"
14298
with (test_project_dir / "README.md").open() as f:
14399
readme_text = "".join(f.readlines())
144100

@@ -152,18 +108,11 @@ def test_optional_funder(
152108

153109

154110
def test_docs_build(
155-
tmp_path: pathlib.Path,
156111
venv: pytest_venv.VirtualEnvironment,
157112
generate_package: typing.Callable,
158113
) -> None:
159114
"""Test documentation build from package created from template."""
160-
config = {
161-
"github_owner": "test-user",
162-
"project_short_description": "description",
163-
"project_name": "Cookiecutter Test",
164-
}
165-
generate_package(config, tmp_path)
166-
test_project_dir = tmp_path / "cookiecutter-test"
115+
_, test_project_dir = generate_package()
167116
venv.install("tox")
168117
tox_docs_process = subprocess.run( # noqa: S603
169118
[

0 commit comments

Comments
 (0)