microsoft/hve-core

Public

mirrored fromhttps://github.com/microsoft/hve-coreAvailable

CodeCommitsIssuesPull requestsActionsInsightsSecurity
23be43f9eb4e5c4524397014accacc4b303fec29

Branches

Tags

  • No tags available.
0Branches0Tags
Go to file
Add file
Code

Clone

HTTPS

Download ZIP

docs/architecture/testing.md

217lines · modecode

1---
2title: Testing Architecture
3description: PowerShell Pester test infrastructure and conventions
4sidebar_position: 4
5author: Microsoft
6ms.date: 2026-05-20
7ms.topic: concept
8---
9
10## Overview
11
12HVE Core uses Pester 5.x for PowerShell testing with a mirror directory structure that maps production scripts to their corresponding test files. The test infrastructure supports isolated unit testing through mock utilities and enforces an 80% code coverage threshold.
13
14## Directory Structure
15
16Test files follow a mirror pattern where each script directory has a corresponding `tests/` subdirectory:
17
18```text
19scripts/
20├── collections/
21│ └── *.ps1
22├── extension/
23│ ├── Package-Extension.ps1
24│ └── Prepare-Extension.ps1
25├── lib/
26│ └── Get-VerifiedDownload.ps1
27├── linting/
28│ └── *.ps1
29├── plugins/
30│ └── *.ps1
31├── security/
32│ └── *.ps1
33└── tests/
34 ├── collections/
35 ├── extension/
36 ├── lib/
37 ├── linting/
38 ├── plugins/
39 ├── security/
40 ├── Fixtures/
41 ├── Mocks/
42 │ └── GitMocks.psm1
43 └── pester.config.ps1
44```
45
46Test files use the `.Tests.ps1` suffix convention, enabling automatic discovery by Pester.
47
48## Pester Configuration
49
50The configuration file at [scripts/tests/pester.config.ps1](https://github.com/microsoft/hve-core/blob/main/scripts/tests/pester.config.ps1) defines test execution behavior:
51
52```powershell
53# Key configuration settings
54$configuration.Run.TestExtension = '.Tests.ps1'
55$configuration.Filter.ExcludeTag = @('Integration', 'Slow')
56$configuration.CodeCoverage.CoveragePercentTarget = 80
57```
58
59### Coverage Configuration
60
61Code coverage analyzes scripts in production directories while excluding test files:
62
63| Setting | Value |
64|-------------------|---------------------|
65| Coverage target | 80% minimum |
66| Output format | JaCoCo XML |
67| Output path | `logs/coverage.xml` |
68| Excluded patterns | `*.Tests.ps1` |
69
70Coverage directories include `linting/`, `security/`, `lib/`, `extension/`, `plugins/`, `collections/`, and `tests/`.
71
72### Test Output
73
74| Output Type | Format | Path |
75|-----------------|----------|---------------------------|
76| Test results | NUnitXml | `logs/pester-results.xml` |
77| Coverage report | JaCoCo | `logs/coverage.xml` |
78
79## Test Utilities
80
81### LintingHelpers Module
82
83The [LintingHelpers.psm1](https://github.com/microsoft/hve-core/blob/main/scripts/linting/Modules/LintingHelpers.psm1) module provides shared functions for linting scripts and tests:
84
85| Function | Purpose |
86|---------------------------|-----------------------------------------------------------------|
87| `Get-ChangedFilesFromGit` | Detects changed files using merge-base with fallback strategies |
88| `Get-FilesRecursive` | Finds files via `git ls-files` with `Get-ChildItem` fallback |
89| `Get-GitIgnorePatterns` | Parses `.gitignore` into PowerShell wildcard patterns |
90| `Write-GitHubAnnotation` | Writes GitHub Actions annotations for errors and warnings |
91| `Set-GitHubOutput` | Sets GitHub Actions output variables |
92| `Set-GitHubEnv` | Sets GitHub Actions environment variables |
93
94### GitMocks Module
95
96The [GitMocks.psm1](https://github.com/microsoft/hve-core/blob/main/scripts/tests/Mocks/GitMocks.psm1) module provides reusable mock helpers for Git CLI and GitHub Actions testing.
97
98#### Environment Management
99
100| Function | Purpose |
101|------------------------------------|---------------------------------------------------------|
102| `Save-GitHubEnvironment` | Saves current GitHub Actions environment variables |
103| `Restore-GitHubEnvironment` | Restores saved environment state |
104| `Initialize-MockGitHubEnvironment` | Creates mock GitHub Actions environment with temp files |
105| `Clear-MockGitHubEnvironment` | Removes GitHub Actions environment variables |
106| `Remove-MockGitHubFiles` | Cleans up temp files from mock initialization |
107
108#### Git Mocks
109
110| Function | Purpose |
111|-------------------------------|---------------------------------------------------|
112| `Initialize-GitMocks` | Sets up standard git command mocks for a module |
113| `Set-GitMockChangedFiles` | Updates files returned by git diff mock |
114| `Set-GitMockMergeBaseFailure` | Simulates merge-base failure for fallback testing |
115
116#### Test Data
117
118| Function | Purpose |
119|---------------------------|---------------------------------------------------|
120| `New-MockFileList` | Generates mock file paths for testing |
121| `Get-MockGitDiffScenario` | Returns predefined scenarios for git diff testing |
122
123### Environment Save/Restore Pattern
124
125Tests that modify environment variables follow this pattern:
126
127```powershell
128BeforeAll {
129 Import-Module "$PSScriptRoot/../Mocks/GitMocks.psm1" -Force
130}
131
132BeforeEach {
133 Save-GitHubEnvironment
134 $script:MockFiles = Initialize-MockGitHubEnvironment
135}
136
137AfterEach {
138 Remove-MockGitHubFiles -MockFiles $script:MockFiles
139 Restore-GitHubEnvironment
140}
141```
142
143## Running Tests
144
145### npm Scripts
146
147| Command | Description |
148|-------------------|---------------------------------|
149| `npm run test:ps` | Run all PowerShell Pester tests |
150| `npm run test:py` | Run all Python tests via pytest |
151
152### Direct Pester Invocation
153
154Run tests with default configuration:
155
156```powershell
157Invoke-Pester -Configuration (& ./scripts/tests/pester.config.ps1)
158```
159
160Run tests with code coverage:
161
162```powershell
163Invoke-Pester -Configuration (& ./scripts/tests/pester.config.ps1 -CodeCoverage)
164```
165
166Run tests in CI mode with exit codes and NUnit output:
167
168```powershell
169Invoke-Pester -Configuration (& ./scripts/tests/pester.config.ps1 -CI -CodeCoverage)
170```
171
172Run a specific test file:
173
174```powershell
175Invoke-Pester -Path ./scripts/tests/linting/Invoke-PSScriptAnalyzer.Tests.ps1
176```
177
178### Test Utility Scripts
179
180Two wrapper scripts in `scripts/tests/` streamline test execution:
181
182* `Invoke-PesterTests.ps1` orchestrates full test runs with configuration loading, code coverage, CI output formatting, and result file generation. The `npm run test:ps` command calls this script.
183* `Get-ChangedTestFiles.ps1` identifies test files affected by recent changes, enabling targeted test runs during development or in pull request workflows.
184
185See [scripts/tests/README.md](https://github.com/microsoft/hve-core/blob/main/scripts/tests/README.md) for parameters and usage details.
186
187## Skills Testing
188
189Skill scripts use a co-located test pattern instead of the mirror directory structure used by `scripts/`. Each skill contains its own `tests/` subdirectory:
190
191```text
192.github/skills/<skill-name>/
193├── scripts/
194│ ├── convert.ps1
195│ └── convert.sh
196└── tests/
197 └── convert.Tests.ps1
198```
199
200### Coverage Integration
201
202The Pester configuration at `scripts/tests/pester.config.ps1` resolves skill scripts from the repository root for code coverage analysis. When you include a skill `tests/` directory in an `Invoke-Pester -Path` argument or test run configuration, Pester discovers the skill test files through the `.Tests.ps1` naming convention.
203
204Coverage path resolution for skills uses the repository root rather than `$scriptRoot` (which points to `scripts/`):
205
206```powershell
207$repoRoot = Split-Path $scriptRoot -Parent
208$skillScripts = Get-ChildItem -Path (Join-Path $repoRoot '.github/skills') `
209 -Include '*.ps1', '*.psm1' -Recurse -File -ErrorAction SilentlyContinue |
210 Where-Object { $_.FullName -notmatch '\.Tests\.ps1$' }
211```
212
213### Packaging Exclusion
214
215Co-located `tests/` directories are excluded from the VSIX extension package by `Package-Extension.ps1`. After copying a skill directory, the packaging script removes any `tests/` subdirectories from the destination.
216
217🤖 *Crafted with precision by ✨Copilot following brilliant human instruction, then carefully refined by our team of discerning human reviewers.*