Follow-up test improvements for Aspire.Hosting.Maui.Tests (#14768)
- Dominant language
- C#
- Stars
- 6.3k
- Forks
- 991
- Avg merge
- 2d 15h
- Merged PRs (30d)
- 196
Description
Follow-up work from #14768, which added `Aspire.Hosting.Maui.Tests` to CI. Two independent reviews (Opus 4.8, GPT-5.5) surfaced test-quality gaps that were left out of that PR to keep it focused. Each falsifiability gap below was **proven empirically** — production code was mutated to introduce the exact regression described, the suite stayed green, and the mutation was reverted.
Baseline for the runs below: macOS (Darwin, arm64), 132 total / 129 passed / 3 skipped.
### 1. Unsupported-platform tests skip on the supported OS
`tests/Aspire.Hosting.Maui.Tests/MauiUnsupportedPlatformTests.cs` — the Windows/MacCatalyst/iOS tests `Assert.Skip` + `return` on the supported OS (lines 18, 46, 74, 102), so the *supported* path (annotation **absent**) is never asserted. The annotation is added only when `!isSupported()` (`MauiPlatformHelper.cs:102-107`).
**Proof:** forcing Mac + iOS `isSupported` to `() => false` left `MauiUnsupportedPlatformTests` at 4 passed / 3 skipped / **0 failed** on macOS — an "always unsupported" regression goes uncaught.
**Fix:** build the resource unconditionally, then assert both branches:
```csharp
var annotation = windows.Resource.Annotations.OfType().FirstOrDefault();
if (OperatingSystem.IsWindows())
{
Assert.Null(annotation); // supported host: must be absent
}
else
{
Assert.NotNull(annotation); // unsupported host: present
Assert.Contains("Windows", annotation.Reason);
}
```
### 2. Multi-TFM args test asserts too weakly
`MauiWithArgsTests.cs` `AllPlatforms_ArgsStartWithRun` (assertion at 291-293) is the only multi-TFM test, but only checks `args[0] == "run"`. The per-platform tests assert exact TFM but use single-TFM project content (`MauiTestHelper.CreateProjectContent`), so a `GetPlatformTargetFramework` regression returning the whole `;`-joined list, or the wrong TFM, is invisible.
**Proof:** making `ProjectFileReader.GetPlatformTargetFramework` return the whole `TargetFrameworks` value for every platform left `MauiWithArgsTests` at 12 passed / **0 failed**.
**Fix:** assert exact `-f ` per platform in the multi-TFM test:
```csharp
static void AssertTfm(IReadOnlyList args, string expectedTfm)
{
var i = args.ToList().IndexOf("-f");
Assert.True(i >= 0 && i + 1 < args.Count, "expected -f ");
Assert.Equal(expectedTfm, args[i + 1]);
}
```
This catches both the "returns whole `;` list" and "wrong platform TFM" regressions.
### 3. Android semicolon-encoding only unit-tested in isolation
Android env-var encoding happens only inside `CreateAndroidEnvironmentTargetsFileAsync` (`MauiEnvironmentHelper.cs:52`); `GenerateAndroidTargetsFileContent` emits the raw value. `EncodeSemicolons_EncodesCorrectly` calls `EncodeSemicolons` directly, so removing the encode call is invisible.
**Proof:** removing the `EncodeSemicolons(...)` call at line 52 left the full suite at 129 passed / **0 failed**.
**Asymmetry:** iOS encodes inline inside `GenerateiOSTargetsFileContent` (line 279), so `GenerateiOSTargetsFileContent_EncodesSemicolonsInValues` genuinely covers it. Android has no equivalent because its encode lives at a different layer than its tests.
**Fix (two options):**
- Add an integration test through `CreateAndroidEnvironmentTargetsFileAsync` (needs a test `IFileSystemService`, none exists in the project yet) asserting `%3B` appears and the raw `;` does not in the generated `_GeneratedAndroidEnvironment` file; **or**
- Move the encode into `GenerateAndroidTargetsFileContent` (mirroring iOS), which a cheap generator-level test then covers.
### 4. Migrate `MauiTestHelper` temp plumbing to the shared `TestTempDirectory`
`MauiTestHelper.CreateTempProjectFile` / `CleanupTempFile` hand-roll temp-dir creation and manual `try`/`finally` cleanup in every test. The repo already has `tests/Shared/TempDirectory.cs` → `TestTempDirectory : IDisposable` (self-cleaning via `using`), used in ~75 test files.
**Change:** include `` in `Aspire.Hosting.Maui.Tests.csproj`, replace the temp plumbing with `using var dir = new TestTempDirectory();`, and keep only `CreateProjectContent` in the helper. Removes the manual-cleanup boilerplate from each test.
---
Items 1–3 are correctness/falsifiability gaps (a regression would ship undetected); item 4 is a maintainability cleanup. They can be addressed in a single PR or split as convenient.
Contributor guide
Assessment
This issue has not been assessed yet.