Skip to content

Commit ad7e050

Browse files
Align module test layout profiles
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
1 parent 993ae01 commit ad7e050

1 file changed

Lines changed: 34 additions & 9 deletions

File tree

src/docs/Modules/Standards.md

Lines changed: 34 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ Keep related things together so the connection between code and its context is v
107107

108108
- `#Requires -Modules` belongs in the function files that use the dependency, not in a central manifest.
109109
- Parameter descriptions are `#` comments directly above each parameter in `param()`, not `.PARAMETER` blocks.
110-
- Tests for a public function live alongside it, not in a separate unrelated folder.
110+
- Tests follow the same domain boundaries as public source: cover every public command under `tests/`, and align grouped suites with `src/functions/public/<Group>/`.
111111

112112
### Linear versioning
113113

@@ -287,17 +287,42 @@ On abandoned (closed without merge) PRs, the pipeline cleans up any prerelease t
287287

288288
## Tests
289289

290-
- Pester tests under `tests/`.
291-
- Filenames: `<ModuleName>.Tests.ps1` or `<Function>.Tests.ps1`.
292-
- One test file per public command for unit tests; integration tests grouped by scenario.
293-
- Tests run against the built module artifact installed locally, across a multi-OS matrix (Linux, macOS, Windows).
290+
Keep Pester tests under `tests/`. Every public command's behavior must be covered, but commands do not require separate test files. The framework's `FunctionTest` check confirms that every public command is referenced somewhere under `tests/`, so a grouped suite satisfies the structural check; the suite must still assert the command's behavior.
291+
292+
The profiles below are repository layout conventions, not Process-PSModule configuration modes. Use the simplest profile that keeps the suite readable:
293+
294+
| Profile | Test layout |
295+
| ------- | ----------- |
296+
| **Simple** | One root `tests/<ModuleName>.Tests.ps1` file covers the module. |
297+
| **Standard** | One root `tests/<Group>.Tests.ps1` file per public function group. Ungrouped commands and cross-cutting scenarios may remain in separate root `*.Tests.ps1` files. |
298+
| **Advanced** | Organize tests in recursive subdirectories. Process-PSModule discovers each directory independently using the precedence below. |
299+
300+
For the Advanced profile, Process-PSModule traverses `tests/` and every subdirectory. Within each directory:
301+
302+
1. Exactly one `*.Configuration.ps1` file is the only discovered test entry. More than one configuration file in the same directory is an error.
303+
2. Otherwise, one or more `*.Container.ps1` files are all discovered, and `*.Tests.ps1` files in that directory are ignored.
304+
3. Otherwise, all `*.Tests.ps1` files in that directory are discovered.
305+
306+
Process-PSModule derives `TestName` from the file's basename before the first dot. For example, `Projects.Unit.Tests.ps1` produces `Projects`. Use a unique first-dot prefix for every discovered entry so matrix jobs and result artifacts are unambiguous.
307+
308+
Each `*.Tests.ps1` file must declare the Pester 6 requirement:
309+
310+
```powershell
311+
#Requires -Modules @{ ModuleName = 'Pester'; ModuleVersion = '6.0.0'; MaximumVersion = '6.*' }
312+
```
313+
314+
Tests run against the built module artifact installed locally, across a multi-OS matrix (Linux, macOS, Windows). The full suite must also remain runnable locally without mandatory cloud resources, special access, or secrets that cannot be mocked.
315+
316+
Unit tests mock boundaries owned by the module, not third-party APIs or SDKs directly. Wrap external dependencies behind a thin module-owned interface and fake that interface. Where the external contract matters, back the unit tests with a small integration suite that exercises the live dependency.
294317

295318
### Shared test infrastructure
296319

297-
Tests run in parallel across multiple OS runners. Provision shared infrastructure once rather than inside each test file:
320+
Tests run in parallel across multiple OS runners. When integration tests need shared infrastructure, provision it once rather than inside each test file:
321+
322+
- `tests/BeforeAll.ps1` — special root workflow phase that runs once before the full test matrix. Create shared resources here.
323+
- `tests/AfterAll.ps1` — special root workflow phase that runs once after the full test matrix. Remove shared resources here.
298324

299-
- `tests/BeforeAll.ps1` — runs once before the full test matrix. Create shared resources here.
300-
- `tests/AfterAll.ps1` — runs once after the full test matrix. Remove shared resources here.
325+
These exact root files are detected separately and are not recursive test entries. Nested files with these names do not create workflow phases.
301326

302327
Use `$env:GITHUB_RUN_ID` (stable per workflow run, shared across all runners) for deterministic resource names:
303328

@@ -321,7 +346,7 @@ The CI pipeline automatically tests every source file against the following rule
321346
| `FunctionName` | Filename must match the function or filter name |
322347
| `CmdletBinding` | Every function must have `[CmdletBinding()]` |
323348
| `ParamBlock` | Every function must have a `param()` block |
324-
| `FunctionTest` | Every public function must have a corresponding test |
349+
| `FunctionTest` | Every public function must be referenced by the tests; its behavior must be covered whether the suite is per-command or grouped |
325350

326351
To skip a specific rule for one file only, add a comment at the very top of that file:
327352

0 commit comments

Comments
 (0)