-
Notifications
You must be signed in to change notification settings - Fork 433
Add unit tests to WindowsAppSDK Templates #6432
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
lauren-ciha
wants to merge
8
commits into
main
Choose a base branch
from
user/laurenciha/unit-tests-vsix
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
8 commits
Select commit
Hold shift + click to select a range
ca6880a
Add VSIX unit tests
lauren-ciha f5925b3
Update InfoBar test comments to reflect logging behavior. In order to…
lauren-ciha 8a69887
Add tests to check that hyperlink commands call VS with the correct p…
lauren-ciha 10e7931
Remove redundant Tests .gitignore
lauren-ciha 589e121
Add READMEs to dev/VSIX/WindowsAppSDK.Extension.sln and update
lauren-ciha 7d3a2e6
Fix VSSDK import condition in template csproj files
lauren-ciha caf61af
Revert "Fix VSSDK import condition in template csproj files"
lauren-ciha 6a2c966
Document that VSIX builds require VS/msbuild, not dotnet CLI
lauren-ciha File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Some comments aren't visible on the classic Files Changed page.
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,147 @@ | ||
| # Windows App SDK Visual Studio Extensions | ||
|
|
||
| This directory contains the Visual Studio extensions (VSIX) for Windows App SDK, including project templates, item templates, and project wizards for creating WinUI 3 applications. | ||
|
|
||
| ## Structure | ||
|
|
||
| ``` | ||
| dev/VSIX/ | ||
| ├── Extension/ # VSIX extension packages | ||
| │ ├── Cs/ # C# extension | ||
| │ │ ├── Common/ # Localized VSPackage resource files | ||
| │ │ └── Dev17/ # VS 2022 extension project & manifests | ||
| │ └── Cpp/ # C++ extension | ||
| │ ├── Common/ # Localized VSPackage resource files | ||
| │ └── Dev17/ # VS 2022 extension project, manifests & NuGetPackageList.cs | ||
| ├── ProjectTemplates/ # Visual Studio project templates | ||
| │ ├── Desktop/ # Desktop app templates | ||
| │ │ ├── CSharp/ # SingleProjectPackagedApp, PackagedApp, ClassLibrary, UnitTestApp | ||
| │ │ └── CppWinRT/ # SingleProjectPackagedApp, PackagedApp, UnitTestApp | ||
| │ └── Neutral/ # Platform-neutral templates | ||
| │ └── CppWinRT/ # RuntimeComponent | ||
| ├── ItemTemplates/ # Visual Studio item templates | ||
| │ ├── Desktop/ # Desktop-specific items | ||
| │ │ ├── CSharp/ # BlankWindow | ||
| │ │ └── CppWinRT/ # BlankWindow | ||
| │ └── Neutral/ # Platform-neutral items | ||
| │ ├── CSharp/ # BlankPage, UserControl, TemplatedControl, ResourceDictionary, Resw | ||
| │ └── CppWinRT/ # BlankPage, UserControl, TemplatedControl, ResourceDictionary, Resw | ||
| ├── Shared/ # Shared code used by wizards and extensions | ||
| │ ├── WizardImplementation.cs # Main wizard logic (NuGetPackageInstaller) | ||
| │ ├── WizardInfoBarEvents.cs # InfoBar event handlers (NuGetInfoBarUIEvents) | ||
| │ └── OutputWindowHelper.cs # Output window utilities | ||
| └── Tests/ # Unit tests for VSIX components | ||
| └── WindowsAppSDK.VSIX.UnitTests/ | ||
| ``` | ||
|
|
||
| ## Testing | ||
|
|
||
| ### Unit Tests | ||
|
|
||
| The `Tests/WindowsAppSDK.VSIX.UnitTests` project contains unit tests for the VSIX wizard and UI components, targeting `net8.0-windows10.0.19041.0`. | ||
|
|
||
| #### Test Classes | ||
|
|
||
| 1. **NuGetPackageInstallerTests** (20 tests) — Package parsing, `ProjectFinishedGenerating` behavior, NuGet installation failures, happy-path installation, `ShouldAddProjectItem`, and template-specific package count verification. | ||
|
|
||
| 2. **WizardInfoBarEventsTests** (9 tests) — Null parameter handling, `OnClosed`, constructor storage, `SeeErrorDetails` / `ManageNuGetPackages` hyperlink routing, unknown action context, and non-hyperlink action items. | ||
|
|
||
| 3. **ErrorMessageTests** (8 tests) — `CreateErrorMessage` for InfoBar and MessageBox formats (single/multiple packages, null project fallback, format differences) and `CreateDetailedErrorMessage` content/structure. | ||
|
|
||
| #### Running Tests | ||
|
|
||
| ```powershell | ||
| # Run all VSIX unit tests | ||
| dotnet test dev\VSIX\Tests\WindowsAppSDK.VSIX.UnitTests\WindowsAppSDK.VSIX.UnitTests.csproj | ||
|
|
||
| # Run a specific test class | ||
| dotnet test dev\VSIX\Tests\WindowsAppSDK.VSIX.UnitTests\WindowsAppSDK.VSIX.UnitTests.csproj --filter "FullyQualifiedName~NuGetPackageInstallerTests" | ||
| ``` | ||
|
|
||
| ### Test Infrastructure | ||
|
|
||
| The tests use: | ||
| - **MSTest** — Test framework | ||
| - **Moq** — Mocking framework for VS SDK interfaces | ||
| - **VsTestBase** — Abstract base class that pins culture to `en-US` and configures `ThreadHelper` via reflection so `ThrowIfNotOnUIThread()` passes in tests | ||
|
|
||
| Key helper classes: | ||
| - `VsTestBase` — Configures `JoinableTaskContext` with the test thread as the main thread | ||
| - `MockServiceSetup` — Creates mock `IComponentModel`, `EnvDTE.Project` instances (C# and C++), and provides reflection helpers (`SetPrivateField`, `GetPrivateField`, `InvokePrivateMethod`) | ||
| - `TemplateTestData` — Defines NuGet package lists and `TemplateInfo` metadata for all shipped project templates | ||
|
|
||
| ### Shared Source Linking | ||
|
|
||
| The unit test project compiles the same shared wizard source files used by the extension projects (`WizardImplementation.cs`, `WizardInfoBarEvents.cs`, `OutputWindowHelper.cs`) with the `CSHARP_EXTENSION` constant defined. It also links the C# extension's `VSPackage.resx` and `VSPackage.Designer.cs` for resource string access. | ||
|
|
||
| ## Building | ||
|
|
||
| The VSIX extensions require the Visual Studio SDK (VSSDK) build targets and must be | ||
| built with Visual Studio or `msbuild` from a VS Developer Command Prompt. | ||
| **`dotnet build` is not supported** — the template and extension projects import | ||
| `$(VSToolsPath)\VSSDK\Microsoft.VsSDK.targets`, which is only available when the | ||
| VS SDK workload is installed. Building with `dotnet` CLI will produce MSB4019 errors | ||
| because `$(VSToolsPath)` resolves to the .NET SDK directory, which does not contain | ||
| the VSSDK targets. | ||
|
|
||
| ```powershell | ||
| # Build from repository root (uses msbuild) | ||
| .\BuildAll.ps1 | ||
|
|
||
| # Or build the VSIX solution directly from a VS Developer Command Prompt | ||
| msbuild dev\VSIX\WindowsAppSDK.Extension.sln | ||
| ``` | ||
|
|
||
| > **Note:** Unit tests can still be run with `dotnet test` — the test project does | ||
| > not depend on VSSDK targets. See the [Tests README](Tests/README.md) for details. | ||
|
|
||
| ## Key Components | ||
|
|
||
| ### Wizard Implementation | ||
|
|
||
| `Shared/WizardImplementation.cs` implements the `NuGetPackageInstaller` VS project wizard (`IWizard`) that: | ||
| - Parses the `$NuGetPackages$` replacement parameter to determine required packages | ||
| - Detects project type (C++ via `SolutionVCProjectGuid` vs C#) | ||
| - For C++ projects, installs NuGet packages immediately in `ProjectFinishedGenerating` | ||
| - For C# projects, defers installation until `SolutionRestoreFinished` | ||
| - Constructs error messages (`CreateErrorMessage`, `CreateDetailedErrorMessage`) and displays them via InfoBar or MessageBox | ||
|
|
||
| ### InfoBar Events | ||
|
|
||
| `Shared/WizardInfoBarEvents.cs` implements `NuGetInfoBarUIEvents` (`IVsInfoBarUIEvents`) to handle user interactions with InfoBar hyperlinks: | ||
| - **ManageNuGetPackages** — Opens NuGet Package Manager via DTE command `{25fd982b-8cae-4cbd-a440-e03ffccde106}`, ID `0x100` | ||
| - **SeeErrorDetails** — Writes detailed error information to the VS Output window | ||
|
|
||
| ### Output Window Helper | ||
|
|
||
| `Shared/OutputWindowHelper.cs` provides `ShowMessageInOutputWindow` for writing messages to the VS Output window with proper pane creation, activation, and formatting. | ||
|
|
||
| ## Design Principles | ||
|
|
||
| ### Defensive Programming | ||
|
|
||
| The wizard and UI components follow defensive programming practices: | ||
| - Null checks on all VS service calls | ||
| - Graceful degradation when services are unavailable | ||
| - Error logging to Output window instead of throwing exceptions | ||
| - Try-catch blocks around external service interactions | ||
|
|
||
| ### Robustness | ||
|
|
||
| - InfoBar event handlers never crash the extension | ||
| - Failed package installations show user-friendly error messages | ||
| - Missing VS services log warnings rather than failing silently | ||
|
|
||
| ## Contributing | ||
|
|
||
| When adding new features: | ||
| 1. Add corresponding unit tests in `Tests/WindowsAppSDK.VSIX.UnitTests` | ||
| 2. Follow the defensive programming patterns used in existing code | ||
| 3. Document expected VS service interactions | ||
| 4. Ensure all builds and tests pass before submitting | ||
|
|
||
| ## Related Documentation | ||
|
|
||
| - [Windows App SDK Documentation](https://docs.microsoft.com/windows/apps/windows-app-sdk/) | ||
| - [Coding Guidelines](../../docs/Coding-Guidelines.md) | ||
| - [Contributor Guide](../../docs/contributor-guide.md) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,29 @@ | ||
| <Project> | ||
| <!-- | ||
| Override the VSIX Directory.Build.props for test projects. | ||
| Test projects don't need VSIX-specific build settings. | ||
| --> | ||
| <PropertyGroup> | ||
| <ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally> | ||
| <VSIXBuild>false</VSIXBuild> | ||
| <DeployExtension>false</DeployExtension> | ||
| <EnableDefaultNoneItems>true</EnableDefaultNoneItems> | ||
| <!-- | ||
| Suppress VS threading analyzer warnings in test projects: | ||
| VSSDK005: Avoid instantiating JoinableTaskContext (test setup creates its own) | ||
| VSTHRD002: Synchronous waits on tasks (tests block synchronously by design) | ||
| VSTHRD010: Accessing members on the main thread (tests use mocks/COM interop, | ||
| not the VS UI thread, so ThrowIfNotOnUIThread() would fail at runtime) | ||
| --> | ||
| <NoWarn>$(NoWarn);VSSDK005;VSTHRD002;VSTHRD010</NoWarn> | ||
| </PropertyGroup> | ||
|
|
||
| <!-- Useful folder paths (match VSIX conventions) --> | ||
| <PropertyGroup> | ||
| <RepoRoot>$(MSBuildThisFileDirectory)..\..\..\</RepoRoot> | ||
| <VSIXRootDir>$(MSBuildThisFileDirectory)..\</VSIXRootDir> | ||
| <SharedDir>$(VSIXRootDir)Shared\</SharedDir> | ||
| <ExtensionDir>$(VSIXRootDir)Extension\</ExtensionDir> | ||
| <ProjectTemplatesDir>$(VSIXRootDir)ProjectTemplates\</ProjectTemplatesDir> | ||
| </PropertyGroup> | ||
| </Project> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,56 @@ | ||
| # VSIX Unit Tests | ||
|
|
||
| Unit tests for the Windows App SDK Visual Studio project template wizard and UI components. | ||
|
|
||
| ## Prerequisites | ||
|
|
||
| - .NET 8.0 SDK (target framework: `net8.0-windows10.0.19041.0`) | ||
| - No Visual Studio installation required | ||
|
|
||
| > **Note:** While the VSIX extension and template projects require Visual Studio / | ||
| > `msbuild` to build (they depend on VSSDK targets not available in the `dotnet` CLI), | ||
| > the unit test project uses the SDK-style format and can be built and run with | ||
| > `dotnet test` independently. | ||
|
|
||
| ## Running Tests | ||
|
|
||
| ```powershell | ||
| # Run all VSIX unit tests | ||
| dotnet test dev\VSIX\Tests\WindowsAppSDK.VSIX.UnitTests\WindowsAppSDK.VSIX.UnitTests.csproj --verbosity normal | ||
|
|
||
| # Run a specific test class | ||
| dotnet test dev\VSIX\Tests\WindowsAppSDK.VSIX.UnitTests\WindowsAppSDK.VSIX.UnitTests.csproj --filter "FullyQualifiedName~NuGetPackageInstallerTests" | ||
| ``` | ||
|
|
||
| ## Test Coverage (37 tests) | ||
|
|
||
| | Area | Tests | Description | | ||
| |------|-------|-------------| | ||
| | NuGetPackageInstaller | 20 | Package parsing (standard, empty, C++, unit-test, null), `ProjectFinishedGenerating` (C++ immediate install, C# deferred, project ref storage), installation failures (exception catch, partial failure, null component model / installer / project), happy path (all succeed, `RunFinished` no failures / with failures), `ShouldAddProjectItem`, and template-specific package counts | | ||
| | WizardInfoBarEvents | 9 | Null parameter handling (null element, null action item, both null), `OnClosed`, constructor storage, `SeeErrorDetails` routing, `ManageNuGetPackages` routing, unknown action context, non-hyperlink action item | | ||
| | ErrorMessages | 8 | `CreateErrorMessage` for InfoBar (single/multiple packages, null project fallback) and MessageBox formats, InfoBar vs MessageBox difference, `CreateDetailedErrorMessage` (exception type/message, multiple packages, manual-install instruction) | | ||
|
|
||
| ## Project Structure | ||
|
|
||
| ``` | ||
| Tests/ | ||
| ├── Directory.Build.props # Overrides VSIX build props for test projects | ||
| └── WindowsAppSDK.VSIX.UnitTests/ | ||
| ├── WindowsAppSDK.VSIX.UnitTests.csproj # SDK-style project (net8.0-windows) | ||
| ├── NuGetPackageInstallerTests.cs # Tests for NuGetPackageInstaller wizard | ||
| ├── WizardInfoBarEventsTests.cs # Tests for NuGetInfoBarUIEvents | ||
| ├── ErrorMessageTests.cs # Tests for error message construction | ||
| └── TestHelpers/ | ||
| ├── VsTestBase.cs # Base class: ThreadHelper + culture setup | ||
| ├── MockServiceSetup.cs # Mock factory: IComponentModel, EnvDTE.Project, reflection helpers | ||
| └── TemplateTestData.cs # NuGet package lists and TemplateInfo for all templates | ||
| ``` | ||
|
|
||
| ## Architecture Notes | ||
|
|
||
| - **Shared source linking** — Unit tests compile the same shared wizard source files (`WizardImplementation.cs`, `WizardInfoBarEvents.cs`, `OutputWindowHelper.cs`) with the `CSHARP_EXTENSION` constant defined, matching the C# extension project. | ||
| - **VSPackage resources** — The C# extension's `VSPackage.resx` and `VSPackage.Designer.cs` are linked into the test project so that resource strings (e.g., `Resources._1044`) resolve at runtime. | ||
| - **ThreadHelper configuration** — `VsTestBase` creates a `JoinableTaskContext` with the test thread as the main thread and sets it on `ThreadHelper` via reflection so `ThrowIfNotOnUIThread()` passes. | ||
| - **StartInstallationAsync** — Called directly via reflection, bypassing the `JoinableTaskFactory.Run` wrapper in `ProjectFinishedGenerating` which requires a VS message pump. | ||
| - **Error paths** that call `SwitchToMainThreadAsync` are tested for invocation but not full error message display (requires a VS message pump). | ||
| - **MessageBox interception** — `NuGetPackageInstaller.ShowMessageBox` is a replaceable `Func<>` field, allowing tests to capture and verify MessageBox content without blocking UI. |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Where is the MessageBox class/object coming from?