diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 40da9aa612..71596dd655 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -35,13 +35,38 @@ GitHub. - [Git Cheat Sheet](https://education.github.com/git-cheat-sheet-education.pdf) - [GitHub Flow](https://guides.github.com/introduction/flow/) -#### Forking the microsoftgraph/entra-powershell repository +#### Getting the code -Unless you're working with multiple contributors on the same file, we ask that you fork the -repository and submit your pull request from there. The following guide explains how to fork a -GitHub repo. +There are two ways to contribute code changes: -- [Contributing to GitHub projects](https://guides.github.com/activities/forking/). +**Option 1: Clone directly (recommended for regular contributors)** + +Clone the repository directly and create a feature branch. Pull requests created from branches pushed +directly to the repository will have the CI/CD pipeline run **automatically**. + +```git +git clone https://github.com/microsoftgraph/entra-powershell.git +cd entra-powershell +git checkout -b feature/your-change-description +``` + +**Option 2: Fork the repository** + +External contributors can fork the repository and submit pull requests from their fork. Note that +pull requests from forks **will not** trigger the CI/CD pipeline automatically — an internal +reviewer must manually trigger the pipeline run after reviewing the changes. + +```git +# Fork via GitHub UI, then clone your fork +git clone https://github.com//entra-powershell.git +cd entra-powershell +git remote add upstream https://github.com/microsoftgraph/entra-powershell.git +git checkout -b feature/your-change-description +``` + +> **Note**: Regardless of which option you choose, ensure all tests pass locally before submitting +> your PR. For fork-based PRs, the pipeline will be triggered by an internal reviewer once the +> changes are reviewed. ## Filing Issues @@ -68,13 +93,14 @@ You can find all of the pull requests that opened in the When creating a pull request, keep the following in mind: -- Verify you're pointing to the fork and branch that your changes were made in. +- Verify you're pointing to the branch that your changes were made in. - Choose the correct branch you want your pull request to be merged into. - The **main** branch is for active development; changes in this branch will be in the next Entra PowerShell release. - The pull request template that is provided **must be filled out**. Don't delete or ignore it when the pull request is created. - **_IMPORTANT:_** Deleting or ignoring the pull request template delays the PR review process. +- Once your PR is complete and ready for review, add the **Ready For Review** label to signal the team. - The SLA for reviewing pull requests is **three business days**. ### Pull Request Guidelines @@ -90,6 +116,36 @@ The following guidelines must be followed in **every** pull request that is open - Changes made have corresponding test coverage. - Tests shouldn't include any hardcoded values, such as DisplayName, resource ID, etc. - No existing tests should be skipped. +- All API calls in tests must be mocked — never call the real Microsoft Graph API in unit tests. +- Tests must pass both locally and in CI before a PR is reviewed. + +For detailed instructions on writing and running tests, see the [Testing Guide](development-docs/TESTING.md). + +#### Building and testing locally + +Before submitting a PR, build and validate your changes locally: + +1. **Build the module** — see the [Local Build and Validation Guide](development-docs/LOCAL-BUILD-AND-VALIDATION.md) or [BUILD.md](build/BUILD.md). +2. **Run unit tests** — use Pester to run all tests and ensure zero failures. +3. **Run static analysis** — use PSScriptAnalyzer on your changed files. + +```powershell +# Quick validation workflow +.\build\Install-Dependencies.ps1 -ModuleName Entra +. .\build\Common-functions.ps1 +Create-ModuleHelp -Module Entra +.\build\Create-EntraModule.ps1 -Module 'Entra' +.\build\Create-EntraModule.ps1 -Module 'Entra' -Root +Import-Module .\bin\Microsoft.Entra.psd1 -Force + +# Run tests +Invoke-Pester -Path .\test\Entra\ -Output Detailed + +# Static analysis +Invoke-ScriptAnalyzer -Path .\module\Entra\ -Recurse -Severity Warning +``` + +For the full guide, including safe testing practices and troubleshooting, see the [Local Build and Validation Guide](development-docs/LOCAL-BUILD-AND-VALIDATION.md). ## Microsoft Entra PowerShell documentation contributions diff --git a/README.md b/README.md index 0e11b16c01..d88aa5dc8a 100644 --- a/README.md +++ b/README.md @@ -33,9 +33,9 @@ The following table contains a list of the Microsoft Entra PowerShell modules. | [`Microsoft.Entra`][entrapsgallery] | [![mg]][entrapsgallery] | v1.0 Module | | [`Microsoft.Entra.Beta`][entrapsgallerybeta] | [![mgbeta]][entrapsgallerybeta] | Beta Module | -## Roadmap +## Suggestions -Explore what's coming next on our [public roadmap][public-roadmap] ✨ and [share your suggestions][suggestions] with us! +Have ideas for improvement? [Share your suggestions][suggestions] with us! ## Learn more @@ -52,7 +52,14 @@ Explore what's coming next on our [public roadmap][public-roadmap] ✨ and [shar ## Contribute -To contribute, see [contribution guide](CONTRIBUTING.md). By the way, our documentation ([cmdlet references](./module/docs/) and [conceptual articles][docs-repo]) 🤓 are open source! +To contribute, see the [contribution guide](CONTRIBUTING.md). For local development, these guides will help you get started: + +- **[Local Build and Validation Guide](development-docs/LOCAL-BUILD-AND-VALIDATION.md)** — How to build the module, run tests, and validate your changes locally. +- **[Testing Guide](development-docs/TESTING.md)** — How to write and run unit tests using Pester. +- **[Developer Guide](development-docs/README.md)** — Complete guide for creating cmdlets, design guidelines, and code review process. +- **[Build Instructions](build/BUILD.md)** — Detailed module build steps and FAQs. + +By the way, our documentation ([cmdlet references](./module/docs/) and [conceptual articles][docs-repo]) 🤓 are open source! ## Known Issues @@ -86,6 +93,5 @@ Copyright (c) Microsoft Corporation. All Rights Reserved. Licensed under the MIT [entraPowershellIssues]: htts://aka.ms/entra/ps/issues [azureADRetirement]: https://techcommunity.microsoft.com/blog/microsoft-entra-blog/action-required-msonline-and-azuread-powershell-retirement---2025-info-and-resou/4364991 [learn.microsoft]: https://aka.ms/entra/ps/docs -[public-roadmap]: https://github.com/orgs/microsoftgraph/projects/69/views/1 [suggestions]: https://github.com/microsoftgraph/entra-powershell/discussions [docs-repo]: https://github.com/MicrosoftDocs/entra-powershell-docs/tree/main/docs/conceptual diff --git a/development-docs/LOCAL-BUILD-AND-VALIDATION.md b/development-docs/LOCAL-BUILD-AND-VALIDATION.md new file mode 100644 index 0000000000..efa1a4ccc8 --- /dev/null +++ b/development-docs/LOCAL-BUILD-AND-VALIDATION.md @@ -0,0 +1,330 @@ +# Local Build and Validation Guide + +This guide walks you through the complete process of building, validating, and testing the Microsoft Entra PowerShell module on your local machine. Follow these steps to verify your changes before submitting a pull request. + +## Table of Contents + +- [Quick Start](#quick-start) +- [Detailed Build Steps](#detailed-build-steps) + - [Step 1: Clone and Set Up](#step-1-clone-and-set-up) + - [Step 2: Install Dependencies](#step-2-install-dependencies) + - [Step 3: Build the Module](#step-3-build-the-module) + - [Step 4: Import and Verify](#step-4-import-and-verify) + - [Step 5: Run Tests](#step-5-run-tests) + - [Step 6: Run Static Analysis](#step-6-run-static-analysis) +- [Safe Testing Practices](#safe-testing-practices) +- [Installing a Test Version Locally](#installing-a-test-version-locally) +- [Validating Documentation Changes](#validating-documentation-changes) +- [Complete Build Scripts](#complete-build-scripts) +- [CI/CD Pipeline Expectations](#cicd-pipeline-expectations) + +## Quick Start + +For contributors who want the shortest path to building and testing: + +```powershell +# Clone the repository (use your fork URL if contributing via fork) +git clone https://github.com/microsoftgraph/entra-powershell.git +cd entra-powershell + +# Install dependencies +.\build\Install-Dependencies.ps1 -ModuleName Entra + +# Install help generation tool +Install-Module -Name PlatyPS -Scope CurrentUser -Force + +# Build the module +. .\build\Common-functions.ps1 +Create-ModuleHelp -Module Entra +.\build\Create-EntraModule.ps1 -Module 'Entra' +.\build\Create-EntraModule.ps1 -Module 'Entra' -Root + +# Import the module +Import-Module .\bin\Microsoft.Entra.psd1 -Force + +# Run tests +Invoke-Pester -Path .\test\Entra\ -Output Detailed +``` + +## Detailed Build Steps + +### Step 1: Clone and Set Up + +**Option A: Clone directly (recommended)** + +```powershell +git clone https://github.com/microsoftgraph/entra-powershell.git +cd entra-powershell +git checkout -b feature/your-change-description +``` + +**Option B: Fork and clone** + +```powershell +# Fork via GitHub UI first, then: +git clone https://github.com//entra-powershell.git +cd entra-powershell +git remote add upstream https://github.com/microsoftgraph/entra-powershell.git +git checkout -b feature/your-change-description +``` + +> **Note**: PRs from direct clones trigger the CI/CD pipeline automatically. PRs from forks require an internal reviewer to manually trigger the pipeline. + +> **Important**: Always use a **fresh PowerShell session** when building. If a different version of the module dependencies is already loaded in your session, the build will fail. + +### Step 2: Install Dependencies + +The module requires specific versions of the Microsoft Graph PowerShell SDK modules (v2.25.x or later). + +**For the v1.0 module:** + +```powershell +.\build\Install-Dependencies.ps1 -ModuleName Entra +``` + +**For the Beta module:** + +```powershell +.\build\Install-Dependencies.ps1 -ModuleName EntraBeta +``` + +Install the PlatyPS module (required for generating help documentation): + +```powershell +Install-Module -Name PlatyPS -Scope CurrentUser -Force +``` + +> **Tip**: If you get an execution policy error, run: +> ```powershell +> Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser +> ``` + +### Step 3: Build the Module + +**Build help documentation:** + +```powershell +. .\build\Common-functions.ps1 +Create-ModuleHelp -Module Entra +``` + +**Build the module:** + +```powershell +.\build\Create-EntraModule.ps1 -Module 'Entra' +.\build\Create-EntraModule.ps1 -Module 'Entra' -Root +``` + +The built module is output to the `./bin` directory. + +### Step 4: Import and Verify + +Import the built module to verify it loads without errors: + +```powershell +Import-Module .\bin\Microsoft.Entra.psd1 -Force +``` + +Verify the module is loaded: + +```powershell +Get-Module Microsoft.Entra* | Format-Table Name, Version, ExportedCommands +``` + +Test that your cmdlet is available: + +```powershell +Get-Command -Module Microsoft.Entra* -Name +``` + +> **PowerShell 5.1 users**: If you see `Function capacity 4096 exceeded`, run `$MaximumFunctionCount = 32768` before importing. + +### Step 5: Run Tests + +Run all unit tests to ensure nothing is broken: + +```powershell +# Run all v1.0 tests +Invoke-Pester -Path .\test\Entra\ -Output Detailed + +# Or run tests for a specific sub-module +Invoke-Pester -Path .\test\Entra\Users\ -Output Detailed + +# Or run tests for your specific cmdlet +Invoke-Pester -Path .\test\Entra\Users\Get-EntraUser.Tests.ps1 -Output Detailed +``` + +For detailed testing instructions, see the [Testing Guide](./TESTING.md). + +### Step 6: Run Static Analysis + +Run PSScriptAnalyzer on your changed files to catch common issues: + +```powershell +# Analyze a specific file +Invoke-ScriptAnalyzer -Path .\module\Entra\.ps1 -Severity Warning + +# Analyze an entire sub-module +Invoke-ScriptAnalyzer -Path .\module\Entra\Users\ -Recurse -Severity Warning +``` + +## Safe Testing Practices + +When testing changes locally, follow these practices to avoid unintended side effects: + +### Use Mocked Tests (Recommended) + +The project's unit tests use Pester mocks — they **never call the real Microsoft Graph API**. This is the safest way to test: + +```powershell +# This is safe — all API calls are mocked +Invoke-Pester -Path .\test\Entra\Users\Get-EntraUser.Tests.ps1 +``` + +### Use a Test Tenant for Manual Testing + +If you need to manually test cmdlets against a real environment: + +1. **Use a dedicated test/development tenant** — never test against production. +2. **Use least-privilege scopes** — only request the permissions you need: + ```powershell + Connect-Entra -Scopes "User.Read" + ``` +3. **Use read-only operations first** — verify with `Get-` cmdlets before using `Set-`, `New-`, or `Remove-` cmdlets. +4. **Use `-WhatIf` when available** — some cmdlets support `-WhatIf` to preview changes without applying them. +5. **Clean up after testing** — remove any test resources you created. + +### Isolated Testing with a Local Gallery + +To test the module installation experience without affecting your system: + +```powershell +. .\build\Common-functions.ps1 +Create-ModuleFolder +Register-LocalGallery +.\build\Publish-LocalCompatModule.ps1 -Install + +# Test with the installed module +Import-Module Microsoft.Entra -Force + +# Clean up when done +Unregister-LocalGallery +``` + +## Installing a Test Version Locally + +If you want to install your locally-built module system-wide (useful for automation testing): + +```powershell +# Set up a local PowerShell gallery +. .\build\Common-functions.ps1 +Create-ModuleFolder +Register-LocalGallery + +# Publish and install from local gallery +.\build\Publish-LocalCompatModule.ps1 -Install + +# Now import without specifying a path +Import-Module Microsoft.Entra -Force +``` + +To clean up: + +```powershell +# Unregister the local gallery +Unregister-LocalGallery + +# Uninstall the test module +Uninstall-Module Microsoft.Entra -Force +``` + +## Validating Documentation Changes + +If you've updated cmdlet documentation (markdown files in `module/docs/`): + +### Build and Preview Help + +```powershell +# Rebuild help files +. .\build\Common-functions.ps1 +Create-ModuleHelp -Module Entra + +# Import module with updated help +Import-Module .\bin\Microsoft.Entra.psd1 -Force + +# Verify your help content +Get-Help -Full +Get-Help -Examples +``` + +### Validate Markdown Syntax + +Ensure your documentation markdown is properly formatted: + +- Examples must include `powershell` as the code fence language. +- Parameter descriptions must be present for all parameters. +- At least one example must be included per cmdlet. +- See the [cmdlet reference template](./cmdlet-references-documentation/cmdlet-reference-template.md) for the expected format. + +## Complete Build Scripts + +### v1.0 Module — Full Build and Test + +```powershell +# Start a fresh PowerShell session before running this script +.\build\Install-Dependencies.ps1 -ModuleName Entra +Install-Module -Name PlatyPS -Scope CurrentUser -Force +. .\build\Common-functions.ps1 +Create-ModuleHelp -Module Entra +.\build\Create-EntraModule.ps1 -Module 'Entra' +.\build\Create-EntraModule.ps1 -Module 'Entra' -Root +Import-Module .\bin\Microsoft.Entra.psd1 -Force + +# Run all tests +Invoke-Pester -Path .\test\Entra\ -Output Detailed +``` + +### Beta Module — Full Build and Test + +```powershell +# Start a fresh PowerShell session before running this script +.\build\Install-Dependencies.ps1 -ModuleName EntraBeta +Install-Module -Name PlatyPS -Scope CurrentUser -Force +. .\build\Common-functions.ps1 +Create-ModuleHelp -Module EntraBeta +.\build\Create-EntraModule.ps1 -Module 'EntraBeta' +.\build\Create-EntraModule.ps1 -Module 'EntraBeta' -Root +Import-Module .\bin\Microsoft.Entra.Beta.psd1 -Force + +# Run all tests +Invoke-Pester -Path .\test\EntraBeta\ -Output Detailed +``` + +## PR Pipeline Expectations + +When you open a pull request, the PR pipeline automatically: + +1. **Builds the module** — using Azure Pipelines on Windows. +2. **Runs PSScriptAnalyzer** — static analysis for code quality. +3. **Runs credential scanning** — ensures no secrets are committed. + +To avoid surprises, replicate these checks locally before pushing: + +```powershell +# 1. Build the module (see steps above) + +# 2. Run static analysis +Invoke-ScriptAnalyzer -Path .\module\Entra\ -Recurse -Severity Warning + +# 3. Run all tests +Invoke-Pester -Path .\test\Entra\ -Output Detailed + +# 4. Verify no secrets are in your changes +git diff --cached --name-only # Review staged files +``` + +> **Tip**: The PR review SLA is **three business days**. Complete the [PR template checklist](../CONTRIBUTING.md#pull-request-guidelines) to avoid delays. + +> **Important**: Once your PR is complete and all checks pass, add the **Ready For Review** label to signal the team for review. + +> **Note**: Pull requests from direct branches trigger the CI pipeline automatically. Pull requests from forks require an internal reviewer to manually trigger the pipeline after reviewing the changes. In both cases, ensure all tests pass locally before submitting your PR. diff --git a/development-docs/README.md b/development-docs/README.md index 49c5d9955b..b9f82526e5 100644 --- a/development-docs/README.md +++ b/development-docs/README.md @@ -9,6 +9,7 @@ The Microsoft Entra PowerShell Developer Guide helps you develop and test Entra - [Prerequisites](#prerequisites) - [Environment Setup](#environment-setup) - [GitHub Basics](#github-basics) +- [Local Build and Testing](#local-build-and-testing) - [Creating Cmdlets](#creating-cmdlets) - [PowerShell Cmdlet Design Guidelines](#powershell-cmdlet-design-guidelines) - [Design Review](#design-review) @@ -66,30 +67,77 @@ The following prerequisites should be completed before contributing to the Entra If you don't have experience with Git and GitHub, some of the terminology and process can be confusing. [Here is a guide to understanding the GitHub flow][git-workflow] and [here is a guide to understanding the basic Git commands][git-cheat-sheet]. -To develop in the Entra PowerShell repository locally, you first need to create your own fork. For more information on how to fork, click [here][git-forking]. +There are two ways to get the code and contribute: -Once your fork of the Entra PowerShell repository has been created, you need to clone your fork to your local machine. To do so, run the following command: +**Option 1: Clone directly (recommended)** + +Clone the repository directly and create a feature branch. PRs from direct branches will have the CI/CD pipeline run **automatically**. + +```git +git clone https://github.com/microsoftgraph/entra-powershell.git +cd entra-powershell +git checkout -b feature/your-change-description +``` + +Push your branch and create a PR: ```git -git clone https://github.com//entra-powershell.git +git push origin feature/your-change-description ``` -You now be able to create your own branches, commit changes, and push commits to your fork. +**Option 2: Fork the repository** -**Note**: we recommend adding the _microsoftgraph/entra-powershell_ repository to your list of tracked repositories in Git. This allows you to easily pull changes from the `microsoftgraph/entra-powershell` repository. To do this, run the following command: +External contributors can fork the repo and submit PRs from their fork. Note that the CI/CD pipeline **will not** run automatically for fork-based PRs — an internal reviewer will manually trigger it after reviewing the changes. ```git +# Fork via GitHub UI, then clone your fork +git clone https://github.com//entra-powershell.git +cd entra-powershell git remote add upstream https://github.com/microsoftgraph/entra-powershell.git +git checkout -b feature/your-change-description +``` + +Push your branch and create a PR against the upstream repository: + +```git +git push origin feature/your-change-description ``` -Then, to pull changes from the **main** branch in _microsoftgraph/entra-powershell_ into your local working branch, run the following command: +To keep your branch up to date with the latest changes from **main**: ```git -git pull upstream main +git pull origin main ``` > _The `main` branch is for the next feature release and is actively developed with new features, documentation changes, performance improvements, and bug fixes._ +## Local Build and Testing + +Before submitting a pull request, you must build and test your changes locally. We provide detailed guides to help: + +- **[Local Build and Validation Guide](./LOCAL-BUILD-AND-VALIDATION.md)** — Step-by-step instructions for building the module, importing it, running tests, and performing static analysis. +- **[Testing Guide](./TESTING.md)** — How to write unit tests with Pester, use mocks, and achieve code coverage targets. + +### Quick Validation + +```powershell +# Build the module (use a fresh PowerShell session) +.\build\Install-Dependencies.ps1 -ModuleName Entra +. .\build\Common-functions.ps1 +Create-ModuleHelp -Module Entra +.\build\Create-EntraModule.ps1 -Module 'Entra' +.\build\Create-EntraModule.ps1 -Module 'Entra' -Root +Import-Module .\bin\Microsoft.Entra.psd1 -Force + +# Run all tests +Invoke-Pester -Path .\test\Entra\ -Output Detailed + +# Run static analysis +Invoke-ScriptAnalyzer -Path .\module\Entra\ -Recurse -Severity Warning +``` + +For the Beta module, replace `Entra` with `EntraBeta` in the commands above. + ## Creating Cmdlets ### PowerShell Cmdlet Design Guidelines @@ -172,7 +220,6 @@ Significant contributions are credited in the [misc/acknowledgements](./../misc/ [git-download]: https://git-scm.com/downloads [vscode]: https://code.visualstudio.com/docs/setup/setup-overview [git-workflow]: https://guides.github.com/introduction/flow/ -[git-forking]: https://guides.github.com/activities/forking/ [pull-request]: https://github.com/microsoftgraph/entra-powershell/pulls [release-cadence]: https://learn.microsoft.com/powershell/entra-powershell/entraps-versioning-release-cadence [powershell-gallery]: https://aka.ms/EntraPSGallery diff --git a/development-docs/TESTING.md b/development-docs/TESTING.md new file mode 100644 index 0000000000..cf86207984 --- /dev/null +++ b/development-docs/TESTING.md @@ -0,0 +1,261 @@ +# Testing Guide for Microsoft Entra PowerShell + +This guide provides clear, step-by-step instructions for contributors on how to test changes locally before submitting a pull request. Following these practices ensures code quality and reduces review turnaround time. + +## Table of Contents + +- [Prerequisites](#prerequisites) +- [Test Framework Overview](#test-framework-overview) +- [Running Tests Locally](#running-tests-locally) + - [Running All Tests](#running-all-tests) + - [Running Specific Tests](#running-specific-tests) + - [Running Tests for a Module](#running-tests-for-a-module) +- [Writing Tests](#writing-tests) + - [Test File Structure](#test-file-structure) + - [Mocking Best Practices](#mocking-best-practices) + - [Test Naming Conventions](#test-naming-conventions) +- [Code Coverage](#code-coverage) +- [Test Checklist Before Submitting a PR](#test-checklist-before-submitting-a-pr) +- [Troubleshooting](#troubleshooting) + +## Prerequisites + +Before running tests, ensure you have the following installed: + +- **PowerShell 7+** (recommended) or Windows PowerShell 5.1 +- **Pester** (v5+) — the PowerShell testing framework +- **PSScriptAnalyzer** — for static code analysis +- The module built locally (see [BUILD.md](../build/BUILD.md)) + +Install Pester and PSScriptAnalyzer if not already installed: + +```powershell +Install-Module -Name Pester -Scope CurrentUser -Force -SkipPublisherCheck +Install-Module -Name PSScriptAnalyzer -Scope CurrentUser -Force +``` + +## Test Framework Overview + +Microsoft Entra PowerShell uses the [Pester](https://pester.dev) testing framework. Tests are organized by module and cmdlet: + +``` +test/ +├── Common-Functions.ps1 # Shared test utilities +├── Entra/ # v1.0 module tests +│ ├── Entra.Tests.ps1 # Test runner for all v1.0 tests +│ ├── Applications/ # Application cmdlet tests +│ ├── Users/ # User cmdlet tests +│ ├── Groups/ # Group cmdlet tests +│ ├── DirectoryManagement/ # Directory management tests +│ ├── Governance/ # Governance tests +│ ├── SignIns/ # Sign-in tests +│ ├── Reports/ # Report tests +│ └── Authentication/ # Authentication tests +└── EntraBeta/ # Beta module tests (same structure) +``` + +Each cmdlet has a corresponding `.Tests.ps1` file (for example, `Get-EntraUser.Tests.ps1`). + +## Running Tests Locally + +### Running All Tests + +To run the full test suite for the v1.0 module: + +```powershell +# 1. Build the module first (see build/BUILD.md) +# 2. Run all tests +cd entra-powershell +.\test\Entra\Entra.Tests.ps1 +``` + +For the Beta module: + +```powershell +.\test\EntraBeta\EntraBeta.Tests.ps1 +``` + +### Running Specific Tests + +To run a single test file: + +```powershell +# Run tests for a specific cmdlet +Invoke-Pester -Path .\test\Entra\Users\Get-EntraUser.Tests.ps1 -Output Detailed +``` + +To run tests matching a specific name pattern: + +```powershell +# Run only tests with "Delete" in the name +Invoke-Pester -Path .\test\Entra\Users\ -TagFilter "Delete" -Output Detailed +``` + +### Running Tests for a Module + +To run all tests for a specific sub-module (e.g., Users): + +```powershell +Invoke-Pester -Path .\test\Entra\Users\ -Output Detailed +``` + +### Running Tests with Pester Configuration + +For more control, use a Pester configuration object: + +```powershell +$config = New-PesterConfiguration +$config.Run.Path = ".\test\Entra\Users\" +$config.Run.PassThru = $true +$config.Output.Verbosity = "Detailed" +$config.TestResult.Enabled = $true +$config.TestResult.OutputPath = ".\TestReport\TestResults.xml" + +Invoke-Pester -Configuration $config +``` + +## Writing Tests + +### Test File Structure + +Every test file follows this structure: + +```powershell +# Copyright header +BeforeAll { + # Import the module under test + if ((Get-Module -Name Microsoft.Entra.Users) -eq $null) { + Import-Module Microsoft.Entra.Users + } + Import-Module (Join-Path $PSScriptRoot "..\..\Common-Functions.ps1") -Force + + # Define mock data + $mockUser = { + return @( [PSCustomObject]@{ + Id = "aaaaaaaa-0000-1111-2222-bbbbbbbbbbbb" + DisplayName = "Test User" + UserPrincipalName = "testuser@contoso.com" + }) + } + + # Set up mocks + Mock -CommandName Get-MgUser -MockWith $mockUser -ModuleName Microsoft.Entra.Users + Mock -CommandName Get-EntraContext -MockWith { + @{ Scopes = @("User.Read.All") } + } -ModuleName Microsoft.Entra.Users +} + +Describe "Get-EntraUser" { + Context "Test for Get-EntraUser" { + It "Should return a user by ID" { + $result = Get-EntraUser -UserId "aaaaaaaa-0000-1111-2222-bbbbbbbbbbbb" + $result | Should -Not -BeNullOrEmpty + Should -Invoke -CommandName Get-MgUser -ModuleName Microsoft.Entra.Users -Times 1 + } + + It "Should fail when UserId is empty" { + { Get-EntraUser -UserId } | Should -Throw "Missing an argument*" + } + } +} +``` + +### Mocking Best Practices + +Tests must **never** make real API calls. Always use Pester mocks: + +1. **Mock all Microsoft Graph SDK calls** — Use `Mock -CommandName -MockWith -ModuleName ` for every Graph SDK cmdlet your code calls. + +2. **Mock `Get-EntraContext`** — All cmdlets check for an active connection. Mock this to return a valid context: + ```powershell + Mock -CommandName Get-EntraContext -MockWith { + @{ Scopes = @("User.Read.All") } + } -ModuleName Microsoft.Entra.Users + ``` + +3. **Test the not-connected scenario** — Ensure your cmdlet fails gracefully when not connected: + ```powershell + It "should throw when not connected" { + Mock -CommandName Get-EntraContext -MockWith { $null } -ModuleName Microsoft.Entra.Users + { Get-EntraUser -UserId "test-id" } | Should -Throw "Not connected to Microsoft Graph*" + } + ``` + +4. **Use placeholder IDs** — Never use real resource IDs. Use the format `aaaaaaaa-0000-1111-2222-bbbbbbbbbbbb`. + +5. **Use placeholder names and emails** — Use fictitious names like `contoso.com` domains. + +### Test Naming Conventions + +- **Test file**: Name it the same as the cmdlet — `.Tests.ps1` +- **Describe block**: Use the cmdlet name — `Describe "Get-EntraUser"` +- **Context block**: Group related scenarios — `Context "Test for Get-EntraUser"` +- **It block**: Use descriptive names starting with "Should" — `It "Should return all users when -All is specified"` + +### What to Test + +Every cmdlet test should cover: + +| Scenario | Example | +|----------|---------| +| Success with required parameters | `It "Should return a user by ID"` | +| Success with optional parameters | `It "Should return top N users"` | +| Parameter aliases | `It "Should work with -Id alias"` | +| Missing required parameters | `It "Should fail when UserId is empty"` | +| Invalid parameter values | `It "Should fail when Top is not a number"` | +| Not-connected state | `It "Should throw when not connected"` | +| Pipeline support (if applicable) | `It "Should accept pipeline input"` | +| `-All` switch (if applicable) | `It "Should return all results with -All"` | + +## Code Coverage + +The test runner is configured to target **100% code coverage**. To generate a code coverage report: + +```powershell +$config = New-PesterConfiguration +$config.Run.Path = ".\test\Entra\Users\" +$config.CodeCoverage.Enabled = $true +$config.CodeCoverage.Path = ".\module\Entra\Microsoft.Entra" +$config.CodeCoverage.CoveragePercentTarget = 100 +$config.Output.Verbosity = "Detailed" + +Invoke-Pester -Configuration $config +``` + +Coverage reports are saved to the `TestReport/` directory. + +## Test Checklist Before Submitting a PR + +Before creating a pull request, verify the following: + +- [ ] **All existing tests pass** — Run the full test suite and confirm zero failures. +- [ ] **New cmdlets have corresponding tests** — Every new cmdlet must have a `.Tests.ps1` file. +- [ ] **No hardcoded values** — Tests must not contain real resource IDs, display names, or tenant-specific data. +- [ ] **No skipped tests** — Do not skip existing tests (`-Skip` is not allowed). +- [ ] **Mocks are used for all API calls** — No real Microsoft Graph API calls are made during testing. +- [ ] **Code coverage is maintained** — New code should be fully covered by tests. +- [ ] **PSScriptAnalyzer passes** — Run `Invoke-ScriptAnalyzer` on your changed files: + ```powershell + Invoke-ScriptAnalyzer -Path .\module\Entra\.ps1 -Severity Warning + ``` + +Once all checks pass and your PR is ready, add the **Ready For Review** label to signal the team for review. + +## Troubleshooting + +### Common Issues + +| Issue | Solution | +|-------|----------| +| `Pester not found` | Run `Install-Module -Name Pester -Scope CurrentUser -Force -SkipPublisherCheck` | +| `Function capacity 4096 exceeded` | Set `$MaximumFunctionCount = 32768` before importing modules, or use PowerShell 7+ | +| `Execution policy error` | Run `Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser` | +| `Module not found during tests` | Build the module first using `.\build\Create-EntraModule.ps1` (see [BUILD.md](../build/BUILD.md)) | +| `Assembly already loaded` | Use a **fresh PowerShell session** — don't reuse sessions that have other module versions loaded | +| `Mock not applied` | Verify the `-ModuleName` parameter matches the module your cmdlet is in | + +### Getting Help + +- Check the [FAQ in BUILD.md](../build/BUILD.md#faqs) +- Open a [discussion](https://github.com/microsoftgraph/entra-powershell/discussions) +- File an [issue](https://aka.ms/entra/ps/issues) if you believe there's a bug in the test infrastructure