Install
$ agentstack add skill-davidortinau-maui-skills-maui-unit-testing ✓ scanned · ✓ verified — works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ✓ Network access No
- ✓ Filesystem access No
- ✓ Shell / process execution No
- ✓ Environment & secrets No
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
About
.NET MAUI Unit Testing — Gotchas & Best Practices
For project templates, xUnit examples, ViewModel test patterns, and CLI commands, see references/unit-testing-api.md.
⚠️ TFM Trap: Don't Use Platform-Specific TFMs
net9.0-ios
net9.0;net10.0
⚠️ OutputType Trap: App Project as Test Dependency
If your test project references the app project, the app tries to build as Exe for the test TFM — this fails. Add a conditional OutputType:
Exe
Library
Exe
Common Mistakes
❌ Using Static MAUI APIs in ViewModels
ViewModels that directly call static MAUI APIs are untestable:
// ❌ Untestable — Shell.Current requires a running MAUI app
public async Task GoToDetail(int id)
=> await Shell.Current.GoToAsync($"detail?id={id}");
// ✅ Inject an interface — fully testable
public class MyViewModel(INavigationService nav)
{
public async Task GoToDetail(int id)
=> await nav.GoToAsync($"detail?id={id}");
}
Static APIs to wrap behind interfaces:
Shell.Current→INavigationServiceApplication.Current→ avoid entirelySecureStorage.Default→ISecureStorageConnectivity.Current→IConnectivity
❌ Asserting on UI Bindings Instead of ViewModel State
// ❌ Testing the binding — fragile, needs a running UI
Assert.Equal("Hello", label.Text);
// ✅ Testing the ViewModel — fast, no platform dependency
Assert.Equal("Hello", viewModel.Title);
Assert.True(viewModel.SaveCommand.CanExecute(null));
Mocking Strategy for MAUI Services
| MAUI Service | Mock Strategy | |-------------|---------------| | ISecureStorage | Mock — stub GetAsync/SetAsync | | IPreferences | Mock — stub Get/Set/Remove | | IConnectivity | Mock — return NetworkAccess | | IGeolocation | Mock — return fixed Location | | IFilePicker | Mock — return FileResult | | IMediaPicker | Mock — return FileResult | | Shell navigation | Abstract behind INavigationService | | IDispatcher | Stub Dispatch to invoke action synchronously |
Architecture: Interface-First for Testability
Define service interfaces so ViewModels have zero MAUI platform dependencies:
// ✅ These make your entire ViewModel layer testable
public interface INavigationService
{
Task GoToAsync(string route);
Task GoBackAsync();
}
public interface IDialogService
{
Task ConfirmAsync(string title, string message);
}
Register implementations in MauiProgram.cs; inject interfaces into ViewModels.
Tips
- No
Application.CurrentorShell.Currentin ViewModels — wrap in injectable services - Use
ObservableCollectionand[ObservableProperty](MVVM Toolkit) for testable state - Assert on ViewModel properties and
CanExecute, not UI bindings - Use
TaskCompletionSourceto test async waiting flows - Run
dotnet testin CI to catch regressions early - On-device tests: Use
xunit.runner.devicesfor real platform APIs (sensors, camera, Bluetooth)
Checklist
- [ ] Test project targets plain
net9.0/net10.0(not platform-specific TFMs) - [ ] App project has conditional
OutputTypefor test TFM - [ ] All MAUI static APIs wrapped behind injectable interfaces
- [ ] ViewModels tested via properties and commands, not UI bindings
- [ ]
IDispatchermocked to invoke synchronously in tests - [ ]
dotnet testruns green in CI
Source & license
This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: davidortinau
- Source: davidortinau/maui-skills
- License: MIT
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet — be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.