GGua REFERENCE日本語GitHub ↗
GUIDE / VISUAL TESTING

Visual testing guide

Gua.Testing.Visual compares screenshots from a running game with reviewed PNG baselines to detect overlap, clipping, layout shifts, wrong assets, themes, and other defects that can remain even when semantic controls exist and behave correctly. It provides engine-independent visual regression coverage for the rendering contract that semantic assertions cannot prove.

When it adds value

Use visual comparison forPrefer semantic assertions for
Clipping, overlap, and layout shiftsControl existence and visibility
Wrong textures, fonts, themes, or overlaysExpected text and values
Resolution-dependent layout breakageState transitions after actions
Stable UI frameoptionally waitActual PNGfrom diagnosticsReviewed baselinename + variantPixel comparisonthreshold + masksPASS / artifactsreview differences
Figure 1: The baseline is selected by test name and variant; failures preserve all comparison evidence.

Install

Add the latest stable package to a visual test projectpowershell
dotnet add package Gua.Testing.Visual

Create a baseline deliberately

Allow a local baseline updatepowershell
$env:GUA_UPDATE_BASELINES = "1"
dotnet test tests/Game.Visual.Tests/Game.Visual.Tests.csproj
Remove-Item Env:GUA_UPDATE_BASELINES

Review the generated PNG and commit it only when it is correct. Never set this variable in an ordinary pull-request job.

Keep baselines in source control

The comparison below reads from NUnit's test output directory. Add this rule to the test project so committed PNGs under the project-level baselines directory are copied into that output on clean checkouts and CI builds.

Game.Visual.Tests.csprojxml
<ItemGroup>
  <None Update="baselines/**/*.png"
        CopyToOutputDirectory="PreserveNewest" />
</ItemGroup>

When creating or updating a baseline, review the generated output PNG and copy the approved file back to the project's baselines directory before committing it.

Compare in normal test runs

Compare the title screencsharp
using Gua.Testing;
using Gua.Testing.Visual;

// The game publishes this only after transitions and animations are deterministic.
await GuaAssertions.WaitForVisibleAsync(host.Context, "visual-ready");

var baselineVariant = Environment.GetEnvironmentVariable("GUA_VISUAL_VARIANT")
    ?? "windows-unity-mono-1920x1080";

var result = await GuaVisualAssertions.ExpectScreenshotAsync(
    host.Context, "title-screen", new ScreenshotOptions
    {
        BaselineDirectory = Path.Combine(TestContext.CurrentContext.TestDirectory, "baselines"),
        ArtifactDirectory = Path.Combine(TestContext.CurrentContext.WorkDirectory, "artifacts", "gua"),
        BaselineVariant = baselineVariant,
        PixelThreshold = 0.02f,
        MaxDifferentPixelRatio = 0.001,
        WaitForStableSnapshot = true,
        StableFrames = 3,
    });

WaitForStableSnapshot checks that the semantic UI snapshot stopped changing; it does not inspect pixels or prove that sprite, shader, caret, or transition animations stopped. First wait for an explicit application-ready condition and make animation state deterministic, as above. PixelThreshold tolerates small per-channel differences; MaxDifferentPixelRatio limits how many pixels may differ. Tune them only from known stable renderer noise.

Failure evidence

ReasonFiles
pixel_differenceexpected.png, actual.png, diff.png, comparison.json
baseline_missingactual.png, comparison.json
dimension_mismatchexpected.png, actual.png, comparison.json

Set ArtifactDirectory to place visual artifacts beside ordinary Gua diagnostics. Dimension mismatches fail without implicit resizing. Gua.Testing.Visual writes data only and never generates HTML; use the visual-report action to build the static viewer.

Variants, masks, and stability

OptionGood useAvoid
BaselineVariantName legitimate OS, renderer, and resolution differencesCreating a variant for every failure
MasksExclude a clock or truly random avatarMasking important UI
WaitForStableSnapshotConfirm semantic state remains unchanged after an application-ready conditionAssuming it freezes or detects pixel animation
Mask one nondeterministic regioncsharp
Masks = new[]
{
    new GuaMaskRectangle(X: 1710, Y: 24, Width: 180, Height: 48), // clock only
};

CI policy

Upload a browsable pull-request reportyaml
- name: Run visual tests
  id: visual-tests
  shell: pwsh
  env:
    GUA_VISUAL_VARIANT: windows-unity-mono-1920x1080
  run: dotnet test tests/Game.Visual.Tests/Game.Visual.Tests.csproj --configuration Release

- name: Upload visual report
  if: failure()
  uses: link1345/gua-tester/visual-report@v2.2
  with:
    artifact-path: artifacts/gua
    test-outcome: failure
    upload-target: workflow

Keep resolution, DPI, fonts, locale, theme, engine version, renderer, and GPU/driver policy deterministic. Separate baseline updates from ordinary CI and require review of the PNG diff.