Skip to content

Test a slice

NetForge ships two test projects on xUnit v3 + Shouldly + NSubstitute. Both have a _Template folder mirroring the copy-me pattern.

Unit tests (pure, fast)

Copy tests/Tests.Unit/Features/_Template. Unit tests cover validators, mappers, permission matching, and paging math — no host, no database:

csharp
public class CreateProjectValidatorTests
{
    [Fact]
    public void Rejects_empty_name()
    {
        var result = new CreateProjectValidator().Validate(new CreateProjectRequest("", null));
        result.IsValid.ShouldBeFalse();
    }
}

Integration tests (the real pipeline)

Copy tests/Tests.Integration/Features/_Template, rename Template → your domain, point it at your route + permission constants, and drop the Skip. Integration tests run the real pipeline through WebApplicationFactory<Program> against a throwaway SQLite database, with a header-driven auth handler:

csharp
[Collection(IntegrationCollection.Name)]
public class ProjectsEndpointsTests(CustomWebApplicationFactory factory)
{
    [Fact]
    public async Task Create_then_get_round_trips()
    {
        var client = factory.CreateAuthenticatedClient(permissions: [ProjectPermissions.Create, ProjectPermissions.Read]);

        var created = await client.PostAsJsonAsync("/api/projects", new { name = "Apollo" });
        created.StatusCode.ShouldBe(HttpStatusCode.Created);
    }
}

CreateAuthenticatedClient(permissions: [...]) mints a principal with exactly the permissions a scenario needs — so you can assert 401 (no client), 403 (wrong permissions), and 200/201 (granted) in three lines.

Run them

bash
dotnet test NetForge.slnx          # unit + integration
dotnet test tests/Tests.Unit       # unit only (fastest)

NetForge Community is MIT-licensed. Pro is a commercial edition.