From a31c626b26b637b47b30c680276c0cfc16f9d47e Mon Sep 17 00:00:00 2001 From: Marius Storhaug Date: Sun, 5 Apr 2026 14:08:11 +0200 Subject: [PATCH 1/3] Enable code coverage in Test-Module and document framework testing design --- .github/workflows/Test-Module.yml | 3 +++ README.md | 12 ++++++++++++ 2 files changed, 15 insertions(+) diff --git a/.github/workflows/Test-Module.yml b/.github/workflows/Test-Module.yml index 080cfc36..079bdacc 100644 --- a/.github/workflows/Test-Module.yml +++ b/.github/workflows/Test-Module.yml @@ -72,6 +72,9 @@ jobs: Version: ${{ fromJson(inputs.Settings).Version }} WorkingDirectory: ${{ fromJson(inputs.Settings).WorkingDirectory }} Settings: Module + CodeCoverage_Enabled: true + CodeCoverage_OutputFormat: JaCoCo + CodeCoverage_CoveragePercentTarget: 0 Lint-Module: name: Lint-Module (${{ matrix.OSName }}) diff --git a/README.md b/README.md index 24f22c6b..1a2e4888 100644 --- a/README.md +++ b/README.md @@ -163,6 +163,15 @@ The [PSModule - SourceCode tests](./scripts/tests/SourceCode/PSModule/PSModule.T - [PSModule framework settings for style and standards for modules](https://github.com/PSModule/Test-PSModule?tab=readme-ov-file#module-tests) - [PSScriptAnalyzer rules](https://github.com/PSModule/Invoke-ScriptAnalyzer) - This produces a JSON-based report that is used by [Get-PesterTestResults](#get-test-results) evaluate the results of the tests. +- **Code coverage for framework-generated code**: This step also collects code coverage. During the + [build step](#build-module), [Build-PSModule](https://github.com/PSModule/Build-PSModule) injects boilerplate code + into the compiled `.psm1` file — including the `$IsWindows` compatibility shim, type accelerator registration for + public classes and enums, and the `OnRemove` cleanup hook. Because this code is generated by the framework, module + authors have no way to test it themselves. The framework tests in + [Test-PSModule](https://github.com/PSModule/Test-PSModule) exercise these code paths so they are covered. + The coverage artifacts from this step are aggregated with coverage from + [Test-ModuleLocal](#test-module) in the [Get code coverage](#get-code-coverage) step, ensuring that + framework-generated lines no longer appear as uncovered in the module author's coverage report. ### Test module @@ -299,6 +308,9 @@ The [PSModule - Module tests](./scripts/tests/Module/PSModule/PSModule.Tests.ps1 [workflow](./.github/workflows/Get-CodeCoverage.yml) - Gathers the code coverage from the previous steps and creates a summary of the results. +- Coverage is aggregated from both the [Framework test](#framework-test) step (which covers framework-generated + boilerplate) and the [Test module](#test-module) step (which covers module author code). A command that is executed + in either step counts as covered. This ensures module authors are not penalized for lines they did not write. - If the code coverage is below the target, the workflow will fail here. ### Publish module From 8eb60d4c41beef22a3267d898f2619b595c155bf Mon Sep 17 00:00:00 2001 From: Marius Storhaug Date: Sun, 5 Apr 2026 15:23:10 +0200 Subject: [PATCH 2/3] docs: reset Test-Module workflow, rewrite README to imperative voice --- .github/workflows/Test-Module.yml | 3 --- README.md | 23 +++++++++++------------ 2 files changed, 11 insertions(+), 15 deletions(-) diff --git a/.github/workflows/Test-Module.yml b/.github/workflows/Test-Module.yml index 079bdacc..080cfc36 100644 --- a/.github/workflows/Test-Module.yml +++ b/.github/workflows/Test-Module.yml @@ -72,9 +72,6 @@ jobs: Version: ${{ fromJson(inputs.Settings).Version }} WorkingDirectory: ${{ fromJson(inputs.Settings).WorkingDirectory }} Settings: Module - CodeCoverage_Enabled: true - CodeCoverage_OutputFormat: JaCoCo - CodeCoverage_CoveragePercentTarget: 0 Lint-Module: name: Lint-Module (${{ matrix.OSName }}) diff --git a/README.md b/README.md index 1a2e4888..d814a197 100644 --- a/README.md +++ b/README.md @@ -163,15 +163,14 @@ The [PSModule - SourceCode tests](./scripts/tests/SourceCode/PSModule/PSModule.T - [PSModule framework settings for style and standards for modules](https://github.com/PSModule/Test-PSModule?tab=readme-ov-file#module-tests) - [PSScriptAnalyzer rules](https://github.com/PSModule/Invoke-ScriptAnalyzer) - This produces a JSON-based report that is used by [Get-PesterTestResults](#get-test-results) evaluate the results of the tests. -- **Code coverage for framework-generated code**: This step also collects code coverage. During the - [build step](#build-module), [Build-PSModule](https://github.com/PSModule/Build-PSModule) injects boilerplate code - into the compiled `.psm1` file — including the `$IsWindows` compatibility shim, type accelerator registration for - public classes and enums, and the `OnRemove` cleanup hook. Because this code is generated by the framework, module - authors have no way to test it themselves. The framework tests in - [Test-PSModule](https://github.com/PSModule/Test-PSModule) exercise these code paths so they are covered. - The coverage artifacts from this step are aggregated with coverage from - [Test-ModuleLocal](#test-module) in the [Get code coverage](#get-code-coverage) step, ensuring that - framework-generated lines no longer appear as uncovered in the module author's coverage report. +- **Code coverage for framework-generated code**: This step collects code coverage for framework-generated + boilerplate. During the [build step](#build-module), [Build-PSModule](https://github.com/PSModule/Build-PSModule) + injects boilerplate code into the compiled `.psm1` file — including the `$IsWindows` compatibility shim, type + accelerator registration for public classes and enums, and the `OnRemove` cleanup hook. The framework tests in + [Test-PSModule](https://github.com/PSModule/Test-PSModule) exercise these code paths and produce coverage artifacts + that are aggregated with coverage from [Test-ModuleLocal](#test-module) in the + [Get code coverage](#get-code-coverage) step. This keeps framework-generated lines from counting against the module + author's coverage report. ### Test module @@ -308,9 +307,9 @@ The [PSModule - Module tests](./scripts/tests/Module/PSModule/PSModule.Tests.ps1 [workflow](./.github/workflows/Get-CodeCoverage.yml) - Gathers the code coverage from the previous steps and creates a summary of the results. -- Coverage is aggregated from both the [Framework test](#framework-test) step (which covers framework-generated - boilerplate) and the [Test module](#test-module) step (which covers module author code). A command that is executed - in either step counts as covered. This ensures module authors are not penalized for lines they did not write. +- Aggregates coverage from the [Framework test](#framework-test) step (framework-generated boilerplate) and the + [Test module](#test-module) step (module author code). A command executed in either step counts as covered, so + framework-generated lines do not count against the module author's coverage target. - If the code coverage is below the target, the workflow will fail here. ### Publish module From ddb6f12baaf1a35e02094efcb530c4a9451faf03 Mon Sep 17 00:00:00 2001 From: Marius Storhaug Date: Sun, 5 Apr 2026 18:38:01 +0200 Subject: [PATCH 3/3] Update action refs and remove IsWindows shim reference from README --- .github/workflows/Build-Module.yml | 2 +- .github/workflows/Test-Module.yml | 2 +- .github/workflows/Test-SourceCode.yml | 2 +- README.md | 4 ++-- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/Build-Module.yml b/.github/workflows/Build-Module.yml index 56ba0f83..a49da7de 100644 --- a/.github/workflows/Build-Module.yml +++ b/.github/workflows/Build-Module.yml @@ -30,7 +30,7 @@ jobs: fetch-depth: 0 - name: Build module - uses: PSModule/Build-PSModule@7a3ae1be38587e8051833d85ffa53c348de3cd0d # v4.0.13 + uses: PSModule/Build-PSModule@345728124d201f371a8b0f1aacb98f89000a06dc # v4.0.14 with: Name: ${{ fromJson(inputs.Settings).Name }} ArtifactName: ${{ inputs.ArtifactName }} diff --git a/.github/workflows/Test-Module.yml b/.github/workflows/Test-Module.yml index 080cfc36..8f72cc1f 100644 --- a/.github/workflows/Test-Module.yml +++ b/.github/workflows/Test-Module.yml @@ -63,7 +63,7 @@ jobs: path: ${{ fromJson(inputs.Settings).WorkingDirectory }}/outputs/module - name: Test-Module - uses: PSModule/Test-PSModule@d4d6d1d2ac1d243ca82c9c199371533e8d2220ef # v3.0.8 + uses: PSModule/Test-PSModule@8c3337136dc7cf320da39eeb50e776d04bc9ac73 # v3.0.10 with: Name: ${{ fromJson(inputs.Settings).Name }} Debug: ${{ fromJson(inputs.Settings).Debug }} diff --git a/.github/workflows/Test-SourceCode.yml b/.github/workflows/Test-SourceCode.yml index 78ad4041..e5fbd871 100644 --- a/.github/workflows/Test-SourceCode.yml +++ b/.github/workflows/Test-SourceCode.yml @@ -27,7 +27,7 @@ jobs: fetch-depth: 0 - name: Test-SourceCode - uses: PSModule/Test-PSModule@d4d6d1d2ac1d243ca82c9c199371533e8d2220ef # v3.0.8 + uses: PSModule/Test-PSModule@8c3337136dc7cf320da39eeb50e776d04bc9ac73 # v3.0.10 with: Debug: ${{ fromJson(inputs.Settings).Debug }} Prerelease: ${{ fromJson(inputs.Settings).Prerelease }} diff --git a/README.md b/README.md index d814a197..c801a567 100644 --- a/README.md +++ b/README.md @@ -165,8 +165,8 @@ The [PSModule - SourceCode tests](./scripts/tests/SourceCode/PSModule/PSModule.T - This produces a JSON-based report that is used by [Get-PesterTestResults](#get-test-results) evaluate the results of the tests. - **Code coverage for framework-generated code**: This step collects code coverage for framework-generated boilerplate. During the [build step](#build-module), [Build-PSModule](https://github.com/PSModule/Build-PSModule) - injects boilerplate code into the compiled `.psm1` file — including the `$IsWindows` compatibility shim, type - accelerator registration for public classes and enums, and the `OnRemove` cleanup hook. The framework tests in + injects boilerplate code into the compiled `.psm1` file — including type accelerator registration for public classes + and enums, and the `OnRemove` cleanup hook. The framework tests in [Test-PSModule](https://github.com/PSModule/Test-PSModule) exercise these code paths and produce coverage artifacts that are aggregated with coverage from [Test-ModuleLocal](#test-module) in the [Get code coverage](#get-code-coverage) step. This keeps framework-generated lines from counting against the module