Skip to content

Improve integration testing system with new layout and domain-specific assertions#657

Merged
delatrie merged 57 commits into
mainfrom
testing-improvements
Jun 3, 2026
Merged

Improve integration testing system with new layout and domain-specific assertions#657
delatrie merged 57 commits into
mainfrom
testing-improvements

Conversation

@delatrie

@delatrie delatrie commented Jun 2, 2026

Copy link
Copy Markdown
Contributor

Summary

This PR overhauls the integration testing infrastructure and migrates NUnit/Xunit integration tests to a generated, domain-specific assertion DSL for Allure results.

  • biggest changed areas:
    • tests/Allure.NUnit.Tests (layout migration + assertion transition)
    • tests/Allure.Xunit.Tests (layout migration + assertion transition)
    • tests/Allure.Testing (new assertion/model engine)
    • build/Allure.Build.SourceGenerators and build/Allure.Build.Tasks (codegen/tasking for samples + assertions)

What Changed

1) New integration-test layout and sample metadata flow

  • Allowed samples to be nested inside a test project. This allows moving from the overblown Samples directory with all the samples of the project to multiple test-specific samples packed next to the test classes.

    Samples are automatically detected in any Samples folder at any level inside the project. The new naming reflects that: sample projects are named <test-project>.Samples.<parent-folders>.<sample-name>, where <sample-name is the name of the sample file (without extension) or the name of the sample directory inside Samples.

    The registry generator now creates one registry class per Samples directory. The class is created in the namespace that contains Samples. Test classes within this namespace can use AllureSampleRegistry directly.

  • Reorganized tests into domain folders (AllureIds, BddLabels, Links, Fixtures, Tags, etc.) for both NUnit and Xunit.

  • Moved sample property resolution from .props and .targets files to the new FillSampleMetadata build task. The task resolves the following sample properties:

    • SampleName
    • RegistryNamespace
    • ProjectName / ProjectFilePath / ProjectRelativePath
    • ResultsDirectory
    • ProjectBinPath / ProjectObjPath
  • Updated test targets to build and consume the build task assembly (Allure.Build.Tasks.dll) from its original output location

Net effect: sample generation/execution is less convention-fragile and better aligned with nested folder layouts.

2) Sample registry generation redesign

  • AllureSampleRegistryGenerator now groups by RegistryNamespace and SampleName instead of only a project suffix.
  • Generator creates a registry class for each namespace that contains Samples.
  • Registry entries have richer entry docs and run hints. When hovered, the entry shows:
    • the source file in the test project
    • the command to run the generated sample project
    • the path to the default allure-results directory

Net effect: stronger test partitioning and more user-friendly sample hints.

3) New generated custom assertion system for Allure results

  • Added typed Allure result model in tests/Allure.Testing/Assertions/Model/* and property marker interfaces under .../Model/Properties/*.

  • Added assertion primitives in tests/Allure.Testing/Assertions/* for:

    • criteria/equality-based item checks
    • single/one/no/matching item checks
    • property-to-value narrowing
    • collection-to-item narrowing
    • JSON-property presence/absence/value/constraint assertions
  • Added source generator templates/metadata (build/Allure.Build.SourceGenerators/Assertions/*) to derive assertion surface from model/property metadata and interfaces.

  • Added assertion API in tests/Allure.Testing/AllureAssertionExtensions.cs for:

    • root-level collections (test results and containers)
    • raw collections
    • chainings

    Added source-generated assertion API in tests/Allure.Testing/AllureAssertionExtensions.cs for:

    • nested objects
    • object properties
    • nested collection items

Net effect: integration tests now assert semantic Allure structures with domain language instead of manual JSON traversal.

4) Result parsing hardening in sample runner

  • AllureSampleRunner now parses JSON into typed model objects (AllureTestResult, AllureContainer, etc.) and aggregates parse/validation failures.
  • Introduced assertion-style failure reporting for implemented assertions.
  • Removed legacy untyped AllureResults JSON-object record and replaced with typed model-backed results.

Net effect: clearer failures when the sample output shape is invalid.

5) Tooling/runtime alignment updates

  • Dev/test baseline moved to .NET 10 and C# 14 (Directory.Build.props, workflow update).
  • Updated TUnit dependencies to 1.35.2 (TUnit, TUnit.Core, TUnit.Assertions).
  • Set IsTestProject=false and removed TestContainer capability for src/* projects to avoid accidental test discovery in IDE/CLI for non-test projects.

Custom Assertions Added (with examples)

The new DSL is generated, so assertions are consistent across Allure model objects and collections.

Root/result-level assertions

Use to assert AllureResults.

  • HasSingleTestResult(...): narrows to the found test result.
  • HasTestResultAt(...): narrows to the test result at a specific index.
  • HasTestResult(...): at least one test result.
  • HasOnlyOneTestResult(...): exactly one test result.
  • HasNoTestResult(...): no test result.
  • HasTestResults([...]): matching all test results.
  • HasSingleContainer(...): narrows to the found container.
  • HasContainerAt(...): narrows to the container at a specific index.
  • HasContainer(...): at least one container.
  • HasOnlyOneContainer(...): exactly one container.
  • HasNoContainer(...): no container.
  • HasContainer([...]): matching all containers.

Example:

await Assert.That(results).HasSingleTestResult()
    .With.Name("Lorem Ipsum");

Property assertions (existence/value/absence)

Use to assert Allure Model objects (like AllureTestResult or AllureLabel):

  • Has<Property>(): narrows to the property value if it exists.
  • HasNo<Property>(): for properties that must be missing.
  • Has<Property>(...): checks for equality/constraints.

Or chain them via .That:

  • .That.Has<Property>()
  • .That.HasNo<Property>()
  • .That.Has<Property>(...)

Alternatively, chain them, via With (omit the Has prefix):

  • .With.<Property>()
  • .With.No<Property>()
  • .With.<Property>(...)

Example:

await Assert.That(testResult).HasName("Lorem Ipsum")
    .And.HasFullName().That.EndsWith(".Test");
await Assert.That(testResult).HasSingleLabel("tag").With.Value("foo");

Collection assertions

Use to assert collections and collection properties like labels:

  • HasSingle<Item>(...): narrows to the found item.
  • Has<Item>At(...): narrows to the item at a specific index.
  • HasOnlyOne<Item>(...): exactly one item.
  • Has<Item>(...): at least one item.
  • HasNo<Item>(...): no item.

When asserting collection properties, you can chain them via .That and .With as with other property assertions.

Example:

await Assert.That(results).HasSingleTestResult()
    .With.LinksMatching([
        link => link.HasUrl("url-1"),
        link => link.HasUrl("url-2"),
    ]);
await Assert.That(results).HasSingleTestResult()
    .That.HasOnlyOneLabel("foo");

Other changes and fixes

  • Allure_GenerateTestSamples now deletes existing sample files that have been removed from the source.
  • Allure_DeleteTestSamples now correctly deletes project output (bin) and intermediate output (obj) directories.
  • Allure_DeleteTestSamples also removes all directories from bin and obj that match the <test-project>.Samples.* pattern. This allows for a proper cleanup of removed samples.
  • Allure_GenerateTestSamples now correctly initializes required properties when run directly.
  • Move sample validation logic from AllureSampleRegistryGenerator to a new MSBuild task.
  • Fix build crash when a test project contains a sample with missing metadata.
  • Fix typos in documentation comments.

Migration Notes

  • The dominant part of the file churn is structural moves/renames of test classes and sample files into domain-specific folders.
  • Assertion migration updates existing tests from low-level checks to fluent domain assertions; behavior intent remains the same, but failures are more targeted.
  • Build targets now rely on resolved sample metadata; custom sample definitions should include or permit derivation of metadata keys used by FillSampleMetadata.

delatrie added 30 commits May 13, 2026 21:17
@delatrie delatrie added the type:internal Change that isn't visible or obvious for end users label Jun 2, 2026
@delatrie delatrie marked this pull request as ready for review June 2, 2026 21:54
@delatrie delatrie requested a review from epszaw June 3, 2026 06:27
@delatrie delatrie merged commit d217edd into main Jun 3, 2026
6 checks passed
@delatrie delatrie deleted the testing-improvements branch June 3, 2026 09:55
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

theme:build theme:workflow type:internal Change that isn't visible or obvious for end users

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants