Key points
- Why testing is non-negotiable in Uno Platform: C# code runs on up to seven runtimes (Windows, macOS, iOS, Android, WebAssembly, Linux, embedded). Code that works on Windows can break in WebAssembly due to memory limits, and smooth iOS animations can stutter on low-end Android. Tests form a "load-bearing wall" that catches bugs at the earliest stage, and TDD elevates them to "executable specifications."
- Testability requires Dependency Injection (DI): A class should not create its own dependencies. The
BadViewModelexample createsnew HttpClient()directly, forcing tests to hit a real network. The recommended pattern defines anIDataServiceinterface, withApiDataServicefor production andMock<IDataService>injected via the constructor ofProductsViewModelin tests. - Unit tests target pure logic in ViewModel/Service layers: They run fast, need no simulator, and follow the Arrange-Act-Assert pattern. xUnit's
[Fact]marks single-case tests;[Theory]+[InlineData]runs the same logic across multiple inputs. - Moq isolates platform APIs: For
WeatherViewModel, which depends onIGeolocationServiceandIWeatherService, mocks return a fixed New York location and weather payload.Times.OnceandTimes.Neververifications confirm interaction contracts, distinguishing Mocks (verify behavior) from Stubs (return data only). - Uno.UITest (Appium-based) handles UI flows: Scripts use
IAppto tapUsernameTextBox, enter text, dismiss the keyboard, tapLoginButton, and assert thatHomeWelcomeTextappears within a timeout. The critical XAML discipline is settingAutomationIdon every locatable element; using visible text (e.g., "登录") would break under localization to "Login". - Snapshot testing catches visual regressions: Tools such as Verify record a baseline rendering (e.g.,
settings_page_screenshot.png) and diff any subsequent run. Best used inside code review, since any intentional UI change forces a manual baseline update. - CI integration preserves test value: A layered strategy pairs fast compile-time unit tests (run on every push) with pre-merge UI tests on device farms. The included GitHub Actions YAML runs
dotnet test --collect:"XPlat Code Coverage"onwindows-latestfor unit tests andmacos-latest(needed for iOS + Android emulators) for UI tests, gated byneeds: unit-tests.
Hands-on exercises
1. Create an xUnit project for an Uno app and write at least five tests around one business-logic class, covering normal, boundary, and exception cases. Use [Theory] + [InlineData] to parameterize.
2. Use Moq to test a class that depends on an external service, simulating varied return data and exception paths.
3. Write Uno.UITest scripts for critical flows such as login and form submission, ensuring every locatable XAML element exposes an AutomationId, then run them against a local emulator.