RepletoryLib.Testing 1.0.0

dotnet add package RepletoryLib.Testing --version 1.0.0
                    
NuGet\Install-Package RepletoryLib.Testing -Version 1.0.0
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="RepletoryLib.Testing" Version="1.0.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="RepletoryLib.Testing" Version="1.0.0" />
                    
Directory.Packages.props
<PackageReference Include="RepletoryLib.Testing" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add RepletoryLib.Testing --version 1.0.0
                    
#r "nuget: RepletoryLib.Testing, 1.0.0"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package RepletoryLib.Testing@1.0.0
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=RepletoryLib.Testing&version=1.0.0
                    
Install as a Cake Addin
#tool nuget:?package=RepletoryLib.Testing&version=1.0.0
                    
Install as a Cake Tool

RepletoryLib.Testing

Unit testing infrastructure with mock services, assertion extensions, and in-memory database factory.

Part of the RepletoryLib ecosystem -- standalone, reusable .NET 10 libraries with zero business logic.

NuGet .NET 10 License: MIT


Overview

RepletoryLib.Testing provides a TestBase class and pre-built mock implementations for unit testing applications built with the RepletoryLib ecosystem. It includes mocks for caching, messaging, user context, tenant context, and date/time, plus FluentAssertions extensions for the Result<T> pattern and an EF Core in-memory database factory.

Key Features

  • TestBase -- Base class with pre-configured DI container and all mocks ready
  • MockCacheService -- In-memory cache with call tracking (GetCalls, SetCalls, RemoveCalls)
  • MockMessagePublisher -- Records published messages with type-safe querying
  • MockCurrentUserService -- Configurable user context (ID, name, roles, permissions, tenant)
  • MockCurrentTenantService -- Configurable tenant context
  • MockDateTimeProvider -- Controllable time with Advance() and SetUtcNow()
  • ResultAssertionExtensions -- FluentAssertions for Result<T> (BeSuccess(), BeFailure(), etc.)
  • InMemoryDbContextFactory<T> -- Creates isolated in-memory EF Core databases per test

Installation

dotnet add package RepletoryLib.Testing

Dependencies

Package Type
RepletoryLib.Common RepletoryLib
RepletoryLib.Caching.Abstractions RepletoryLib
RepletoryLib.Messaging.Abstractions RepletoryLib
RepletoryLib.Utilities.DateAndTime RepletoryLib
xunit NuGet (2.9.3)
Moq NuGet (4.20.72)
FluentAssertions NuGet (7.0.0)
Microsoft.EntityFrameworkCore.InMemory NuGet (10.0.0)

Quick Start

using RepletoryLib.Testing;

public class OrderServiceTests : TestBase
{
    [Fact]
    public async Task CreateOrder_publishes_event_and_caches_result()
    {
        Setup();
        Services.AddTransient<OrderService>();

        var provider = BuildServiceProvider();
        var service = provider.GetRequiredService<OrderService>();

        var result = await service.CreateOrderAsync(new Order { Total = 100m });

        result.Should().BeSuccess();
        MockPublisher.GetPublished<OrderCreatedEvent>().Should().HaveCount(1);
        MockCache.SetCalls.Should().HaveCount(1);
    }
}

Usage Examples

TestBase Setup

TestBase provides a ServiceCollection, mock instances, and a BuildServiceProvider() method:

public class MyServiceTests : TestBase
{
    [Fact]
    public async Task My_test()
    {
        Setup(); // Initialize mocks and service collection

        // Configure mocks
        MockUser.UserId = "user-123";
        MockUser.Permissions.Add("orders.create");
        MockTenant.TenantId = Guid.NewGuid();
        MockDateTime.SetUtcNow(new DateTime(2025, 1, 1));

        // Register your services
        Services.AddTransient<MyService>();

        // Build and resolve
        var provider = BuildServiceProvider();
        var service = provider.GetRequiredService<MyService>();

        // Act and assert
        var result = await service.DoWorkAsync();
        result.Should().BeSuccess();
    }
}

MockCacheService

[Fact]
public async Task Service_caches_result()
{
    Setup();
    Services.AddTransient<ProductService>();
    var provider = BuildServiceProvider();
    var service = provider.GetRequiredService<ProductService>();

    // Pre-populate cache
    await MockCache.SetAsync("product:123", new Product { Name = "Widget" });

    var result = await service.GetProductAsync(Guid.Parse("...123..."));

    // Assert cache interactions
    MockCache.GetCalls.Should().Contain("product:123");
    MockCache.SetCalls.Should().HaveCount(0); // Cache hit, no new set

    // Reset for next test
    MockCache.Reset();
}

MockMessagePublisher

[Fact]
public async Task Order_creation_publishes_event()
{
    Setup();
    Services.AddTransient<OrderService>();
    var provider = BuildServiceProvider();
    var service = provider.GetRequiredService<OrderService>();

    await service.CreateOrderAsync(new Order { Id = Guid.NewGuid(), Total = 500m });

    // Query by message type
    var events = MockPublisher.GetPublished<OrderCreatedEvent>();
    events.Should().HaveCount(1);
    events.First().Total.Should().Be(500m);

    // Query by type and exchange
    var notifications = MockPublisher.GetPublished<OrderNotification>("notifications");
    notifications.Should().HaveCount(1);

    // Total count
    MockPublisher.PublishedCount.Should().Be(2);
}

MockCurrentUserService

[Fact]
public async Task Admin_can_delete_orders()
{
    Setup();
    MockUser.UserId = "admin-001";
    MockUser.UserName = "Admin";
    MockUser.Permissions.Add("orders.delete");
    MockUser.RolesSet.Add("Admin");
    MockUser.TenantId = Guid.NewGuid();

    Services.AddTransient<OrderService>();
    var provider = BuildServiceProvider();
    var service = provider.GetRequiredService<OrderService>();

    // HasPermission("orders.delete") returns true
    var result = await service.DeleteOrderAsync(orderId);
    result.Should().BeSuccess();
}

MockDateTimeProvider

[Fact]
public async Task Subscription_expires_correctly()
{
    Setup();
    MockDateTime.SetUtcNow(new DateTime(2025, 1, 1));

    Services.AddTransient<SubscriptionService>();
    var provider = BuildServiceProvider();
    var service = provider.GetRequiredService<SubscriptionService>();

    var sub = await service.CreateTrialAsync();
    sub.ExpiresAt.Should().Be(new DateTime(2025, 1, 31));

    // Advance time by 32 days
    MockDateTime.Advance(TimeSpan.FromDays(32));

    var isValid = await service.IsValidAsync(sub.Id);
    isValid.Should().BeFalse();
}

Result Assertion Extensions

[Fact]
public async Task Returns_not_found_for_missing_order()
{
    Setup();
    Services.AddTransient<OrderService>();
    var provider = BuildServiceProvider();
    var service = provider.GetRequiredService<OrderService>();

    var result = await service.GetOrderAsync(Guid.NewGuid());

    result.Should().BeFailure()
        .And.HaveStatusCode(404)
        .And.HaveError("not found");
}

[Fact]
public async Task Returns_order_on_success()
{
    // ...
    var result = await service.GetOrderAsync(existingId);

    result.Should().BeSuccess()
        .And.HaveData(expectedOrder);
}

InMemoryDbContextFactory

[Fact]
public async Task Repository_persists_entity()
{
    var factory = new InMemoryDbContextFactory<AppDbContext>();
    var context = factory.Create(); // Unique isolated DB each call

    context.Products.Add(new Product { Name = "Widget", Price = 9.99m });
    await context.SaveChangesAsync();

    var found = await context.Products.FirstOrDefaultAsync();
    found.Should().NotBeNull();
    found!.Name.Should().Be("Widget");
}

API Reference

TestBase Members

Member Type Description
Services IServiceCollection DI container for registering services
MockCache MockCacheService Cache mock with call tracking
MockPublisher MockMessagePublisher Message publisher mock
MockUser MockCurrentUserService User context mock
MockTenant MockCurrentTenantService Tenant context mock
MockDateTime MockDateTimeProvider Controllable time mock
Setup() void Initialize all mocks and register them in DI
BuildServiceProvider() IServiceProvider Build the DI container

Result Assertions

Assertion Description
.Should().BeSuccess() Assert IsSuccess == true
.Should().BeFailure() Assert IsSuccess == false
.And.HaveStatusCode(code) Assert specific status code
.And.HaveData(expected) Assert Data equals expected
.And.HaveError(substring) Assert Error contains substring

Integration with Other RepletoryLib Packages

Package Relationship
RepletoryLib.Common ICurrentUserService, ICurrentTenantService, Result<T>
RepletoryLib.Caching.Abstractions MockCacheService implements ICacheService
RepletoryLib.Messaging.Abstractions MockMessagePublisher implements IMessagePublisher
RepletoryLib.Utilities.DateAndTime MockDateTimeProvider implements IDateTimeProvider
RepletoryLib.Testing.Fixtures Extends this package with Testcontainer-based integration tests

License

This project is licensed under the MIT License.

Copyright (c) 2024-2026 Repletory.


For complete documentation, infrastructure setup, and configuration reference, see the RepletoryLib main repository.

Product Compatible and additional computed target framework versions.
.NET net10.0 is compatible.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages (1)

Showing the top 1 NuGet packages that depend on RepletoryLib.Testing:

Package Downloads
RepletoryLib.Testing.Fixtures

Integration test fixtures with Testcontainers for RepletoryLib

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
1.0.0 73 3/2/2026