microsoft/hve-core

Public

mirrored from https://github.com/microsoft/hve-coreAvailable

CodeCommitsIssuesPull requestsActionsInsightsSecurity
f3e05d8bfd2fdffd564a003bf162f24d3a3ca44c

Branches

Tags

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

Clone

HTTPS

Download ZIP

docs/architecture/testing.md

200lines · modecode

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