Remove legacy WPF app, flatten WinUI project to repo root, rename namespace
The repo carried two parallel UIs (WPF + WinUI) sharing Models/Services via
cross-directory Link includes. Now that WinUI is the only frontend, collapse
the structure so the WinUI project IS the repo root instead of a nested
sibling folder:
- Delete the WPF project entirely (App.xaml, MainWindow.xaml, csproj) and its
bin/obj output
- Move AmiReel.WinUI/* up to the repo root (App, MainWindow, MainPage,
DialogHelper, Assets, Package.appxmanifest, app.manifest, Properties,
.github/instructions, AGENTS.md) via git mv, preserving history
- Rename AmiReel.WinUI.csproj -> AmiReel.csproj; regenerate the solution as
AmiReel.slnx (the newer XML solution format) with a single project
- Rename namespace AmigaDB.VideoRenderer.{Models,Services} -> AmiReel.{...}
and AmiReel_WinUI -> AmiReel across all files, including the embedded
ffmpeg/ffprobe resource logical names in the csproj and ToolExtractor
- Models/ and Services/ no longer need the Link-based cross-directory
<Compile Include>; they're picked up by the SDK's default globbing now
that they live under the project directory
- Rename assets/ -> branding/ (source icon art) to avoid a case-insensitive
collision with Assets/ (packaged tile art) once both sit at repo root
- Merge the two .gitignore files into one; track the PublishProfiles pubxml
files instead of ignoring them (no secrets, and they keep publish
reproducible across machines) as branding, gitignore, etc.
- Simplify publish-win-x64.ps1 (drop the -Target Wpf/WinUI switch, there's
only one target now) and rewrite README.md to describe the single-project
layout, build/run/publish commands, and file structure
Verified: dotnet build succeeds for both AmiReel.csproj and AmiReel.slnx, and
the built exe launches and renders identically to before the move.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,284 @@
|
||||
---
|
||||
description: 'Unit testing standards, test project setup, naming, build & run commands'
|
||||
applyTo: '**/*Tests.cs, **/*Test.cs, **/*.Tests.csproj'
|
||||
---
|
||||
|
||||
# Testing — Unit Tests, Build & Run
|
||||
|
||||
Every public method and class must have corresponding unit tests. Tests are not optional.
|
||||
|
||||
---
|
||||
|
||||
## 1. Test Framework & Project Setup
|
||||
|
||||
### Recommended Stack
|
||||
|
||||
| Component | Package | Purpose |
|
||||
|---|---|---|
|
||||
| Test Framework | `MSTest` | Test runner & assertions |
|
||||
| Mocking | `Moq` | Mock dependencies |
|
||||
| UI Testing | `Microsoft.Windows.Apps.Test` | WinUI UI automation (optional) |
|
||||
|
||||
### Test Project Setup
|
||||
|
||||
Create a test project alongside the main project:
|
||||
|
||||
```
|
||||
<SolutionRoot>/
|
||||
<ProjectName>/ ← Main app project
|
||||
<ProjectName>.Tests/ ← Unit test project
|
||||
```
|
||||
|
||||
Test project `.csproj` should reference the main project:
|
||||
|
||||
```xml
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<!-- Match TargetFramework to the main project's .csproj -->
|
||||
<TargetFramework><!-- same as the main project's .csproj TargetFramework --></TargetFramework>
|
||||
<UseWinUI>true</UseWinUI>
|
||||
<Nullable>enable</Nullable>
|
||||
<IsPackable>false</IsPackable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<!-- Use latest stable versions; do not hard-code version numbers in instructions -->
|
||||
<PackageReference Include="MSTest.TestAdapter" Version="*" />
|
||||
<PackageReference Include="MSTest.TestFramework" Version="*" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="*" />
|
||||
<PackageReference Include="Moq" Version="*" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\<ProjectName>\<ProjectName>.csproj" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 2. Test Writing Rules
|
||||
|
||||
### What to Test
|
||||
- **All public methods** in ViewModels, Services, Helpers, and Models.
|
||||
- **Edge cases** — null inputs, empty collections, boundary values.
|
||||
- **Error paths** — exception handling, invalid state transitions.
|
||||
- **Business logic** — calculations, transformations, state management.
|
||||
|
||||
### What NOT to Test (Directly)
|
||||
- XAML layout / visual rendering (use UI tests for that).
|
||||
- Framework internals (e.g., `InitializeComponent()`).
|
||||
- Private methods — test them indirectly through public methods.
|
||||
|
||||
### Test Naming Convention
|
||||
|
||||
Use the pattern: `MethodName_Scenario_ExpectedResult`
|
||||
|
||||
```csharp
|
||||
[TestMethod]
|
||||
public void CalculateTotal_WithEmptyCart_ReturnsZero() { }
|
||||
|
||||
[TestMethod]
|
||||
public void LoadDataAsync_WhenServiceThrows_SetsErrorState() { }
|
||||
|
||||
[TestMethod]
|
||||
public async Task SaveAsync_WithValidInput_ReturnsTrue() { }
|
||||
```
|
||||
|
||||
### Test Structure (AAA Pattern)
|
||||
|
||||
Every test follows **Arrange → Act → Assert**:
|
||||
|
||||
```csharp
|
||||
[TestMethod]
|
||||
public void Add_TwoPositiveNumbers_ReturnsSum()
|
||||
{
|
||||
// Arrange
|
||||
var calculator = new Calculator();
|
||||
|
||||
// Act
|
||||
int result = calculator.Add(2, 3);
|
||||
|
||||
// Assert
|
||||
Assert.AreEqual(5, result);
|
||||
}
|
||||
```
|
||||
|
||||
### ViewModel Testing Example
|
||||
|
||||
```csharp
|
||||
[TestMethod]
|
||||
public async Task LoadItemsAsync_OnSuccess_PopulatesItems()
|
||||
{
|
||||
// Arrange
|
||||
var mockService = new Mock<IDataService>();
|
||||
mockService
|
||||
.Setup(s => s.GetItemsAsync())
|
||||
.ReturnsAsync(new List<Item> { new("Test") });
|
||||
|
||||
var viewModel = new MainViewModel(mockService.Object);
|
||||
|
||||
// Act
|
||||
await viewModel.LoadItemsAsync();
|
||||
|
||||
// Assert
|
||||
Assert.AreEqual(1, viewModel.Items.Count);
|
||||
Assert.IsFalse(viewModel.IsLoading);
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 3. Test Organization
|
||||
|
||||
### File Structure
|
||||
|
||||
Mirror the main project's folder structure (defined in [winui-best-practices](winui-best-practices.instructions.md)) in the test project. As the main project grows with subfolders under `ViewModels/`, `Services/`, `Views/`, etc., the test project must grow organically in the same way. This alignment enables on-demand test runs scoped to the area you changed:
|
||||
|
||||
```
|
||||
<ProjectName>/ <ProjectName>.Tests/
|
||||
Models/ Models/
|
||||
User.cs UserTests.cs
|
||||
ViewModels/ ViewModels/
|
||||
MainViewModelTests.cs MainViewModelTests.cs
|
||||
Settings/ Settings/
|
||||
ThemeViewModel.cs ThemeViewModelTests.cs
|
||||
Services/ Services/
|
||||
DataService.cs DataServiceTests.cs
|
||||
Auth/ Auth/
|
||||
AuthService.cs AuthServiceTests.cs
|
||||
Helpers/ Helpers/
|
||||
StringHelper.cs StringHelperTests.cs
|
||||
Converters/ Converters/
|
||||
BoolToVisibilityConverter.cs BoolToVisibilityConverterTests.cs
|
||||
```
|
||||
|
||||
### One Test Class per Class Under Test
|
||||
|
||||
```csharp
|
||||
namespace <RootNamespace>.Tests.ViewModels;
|
||||
|
||||
[TestClass]
|
||||
public class MainViewModelTests
|
||||
{
|
||||
// All tests for MainViewModel go here
|
||||
}
|
||||
```
|
||||
|
||||
### Running Tests On-Demand
|
||||
|
||||
After a change, run only the tests related to the affected area instead of the full suite. Detect the platform first (matching the convention in `.github/agents/Agents.md`):
|
||||
|
||||
```powershell
|
||||
# Run from the test project folder
|
||||
cd <ProjectName>.Tests
|
||||
|
||||
# Detect platform once per session (AMD64 -> x64; ARM64/x86 unchanged)
|
||||
$arch = $env:PROCESSOR_ARCHITECTURE
|
||||
$Platform = if ($arch -eq 'AMD64') { 'x64' } else { $arch }
|
||||
|
||||
# Run tests for a specific class
|
||||
dotnet test -c Debug -p:Platform=$Platform --filter "FullyQualifiedName~MainViewModelTests"
|
||||
|
||||
# Run a single test
|
||||
dotnet test -c Debug -p:Platform=$Platform --filter "FullyQualifiedName~MainViewModelTests.LoadItemsAsync_OnSuccess_PopulatesItems"
|
||||
|
||||
# Run all tests in a namespace (e.g., all ViewModel tests)
|
||||
dotnet test -c Debug -p:Platform=$Platform --filter "FullyQualifiedName~Tests.ViewModels"
|
||||
|
||||
# Run tests in a subfolder namespace (e.g., only Settings ViewModels)
|
||||
dotnet test -c Debug -p:Platform=$Platform --filter "FullyQualifiedName~Tests.ViewModels.Settings"
|
||||
|
||||
# Run the full suite (for cross-cutting changes)
|
||||
dotnet test -c Debug -p:Platform=$Platform
|
||||
```
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 4. Test-Specific Commands
|
||||
|
||||
For general build and register commands, see **Build, Run & Deploy** in `.github/agents/Agents.md`.
|
||||
For on-demand test filtering, see **Running Tests On-Demand** above.
|
||||
|
||||
Below are additional test commands:
|
||||
|
||||
### Build Only the Test Project
|
||||
|
||||
```powershell
|
||||
cd <ProjectName>.Tests
|
||||
$arch = $env:PROCESSOR_ARCHITECTURE
|
||||
$Platform = if ($arch -eq 'AMD64') { 'x64' } else { $arch }
|
||||
dotnet build -c Debug -p:Platform=$Platform
|
||||
```
|
||||
|
||||
### Run Tests with Verbose Output
|
||||
|
||||
```powershell
|
||||
dotnet test -c Debug -p:Platform=$Platform --verbosity normal
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 5. Agent Workflow for Tests
|
||||
|
||||
When you write or modify code, follow this sequence:
|
||||
|
||||
1. **Implement the feature or fix** in the main project.
|
||||
2. **Write unit tests** for every new/changed public method.
|
||||
3. **Build** — see **Build, Run & Deploy** in `.github/agents/Agents.md`. Fix all errors and warnings.
|
||||
4. **Run tests** — `dotnet test -c Debug -p:Platform=$Platform` (from the test project folder; detect `$Platform` as shown above) and ensure all pass.
|
||||
5. **Review** — Confirm tests cover the happy path, edge cases, and error cases.
|
||||
|
||||
### When Modifying Existing Code
|
||||
|
||||
1. **Run existing tests first** to establish a baseline.
|
||||
2. Make the code change.
|
||||
3. **Run tests again** — fix any failures.
|
||||
4. **Add new tests** if the change introduces new behaviour.
|
||||
|
||||
### Coverage Goals
|
||||
|
||||
- Aim for **80%+ code coverage** on business logic (ViewModels, Services).
|
||||
- 100% coverage of utility/helper methods.
|
||||
- UI code-behind is exempt from unit test coverage (tested via integration/UI tests).
|
||||
|
||||
---
|
||||
|
||||
## 6. Common Test Pitfalls
|
||||
|
||||
| Pitfall | Fix |
|
||||
|---|---|
|
||||
| Test depends on another test's state | Each test must be fully independent |
|
||||
| Testing multiple things in one test | One assertion per logical concept |
|
||||
| Tests pass but don't actually verify anything | Always have meaningful assertions |
|
||||
| Mocking too much | Mock only external dependencies, not the class under test |
|
||||
| Testing implementation details | Test behaviour and outcomes, not internal method calls |
|
||||
| Async tests without `await` | Always `await` async methods and use `async Task` return type |
|
||||
|
||||
---
|
||||
|
||||
## Validation
|
||||
|
||||
- Build & run tests — see **Build, Run & Deploy** in `.github/agents/Agents.md`.
|
||||
- Verify all tests pass — zero failures, zero skipped without justification.
|
||||
- Verify naming follows `MethodName_Scenario_ExpectedResult` pattern.
|
||||
- Verify AAA structure (Arrange/Act/Assert) in every test method.
|
||||
- Confirm coverage goals: 80%+ on ViewModels/Services, 100% on helpers.
|
||||
|
||||
---
|
||||
|
||||
## Must Read & Research
|
||||
|
||||
> **Agent Rule:** Before writing or modifying tests, you **must** fetch and review the relevant references below using `fetch_webpage`. Apply what you learn — do not skip this step.
|
||||
|
||||
| # | Reference | When to consult |
|
||||
|---|---|---|
|
||||
| 1 | [Unit testing C# with MSTest](https://learn.microsoft.com/en-us/dotnet/core/testing/unit-testing-with-mstest) | Setting up test project, writing first tests, MSTest attributes |
|
||||
| 2 | [Unit testing best practices .NET](https://learn.microsoft.com/en-us/dotnet/core/testing/unit-testing-best-practices) | Every time you write tests — naming, structure, AAA pattern |
|
||||
| 3 | [Moq Quickstart](https://github.com/devlooped/moq/wiki/Quickstart) | Mocking interfaces, setting up `Returns`/`Throws`, verifying calls |
|
||||
| 4 | [FluentAssertions Documentation](https://fluentassertions.com/introduction) | Writing expressive assertions (`Should().Be()`, collections, exceptions) |
|
||||
| 5 | [dotnet test CLI](https://learn.microsoft.com/en-us/dotnet/core/tools/dotnet-test) | Running tests from terminal, filtering, verbosity options |
|
||||
| 6 | [Test Explorer in Visual Studio](https://learn.microsoft.com/en-us/visualstudio/test/run-unit-tests-with-test-explorer) | Debugging tests, viewing coverage, understanding test output |
|
||||
|
||||
|
||||
Reference in New Issue
Block a user