RepletoryLib.Testing
1.0.0
dotnet add package RepletoryLib.Testing --version 1.0.0
NuGet\Install-Package RepletoryLib.Testing -Version 1.0.0
<PackageReference Include="RepletoryLib.Testing" Version="1.0.0" />
<PackageVersion Include="RepletoryLib.Testing" Version="1.0.0" />
<PackageReference Include="RepletoryLib.Testing" />
paket add RepletoryLib.Testing --version 1.0.0
#r "nuget: RepletoryLib.Testing, 1.0.0"
#:package RepletoryLib.Testing@1.0.0
#addin nuget:?package=RepletoryLib.Testing&version=1.0.0
#tool nuget:?package=RepletoryLib.Testing&version=1.0.0
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.
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 readyMockCacheService-- In-memory cache with call tracking (GetCalls,SetCalls,RemoveCalls)MockMessagePublisher-- Records published messages with type-safe queryingMockCurrentUserService-- Configurable user context (ID, name, roles, permissions, tenant)MockCurrentTenantService-- Configurable tenant contextMockDateTimeProvider-- Controllable time withAdvance()andSetUtcNow()ResultAssertionExtensions-- FluentAssertions forResult<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 | Versions 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. |
-
net10.0
- FluentAssertions (>= 7.0.0)
- Microsoft.EntityFrameworkCore.InMemory (>= 10.0.0)
- Microsoft.NET.Test.Sdk (>= 17.12.0)
- Moq (>= 4.20.72)
- RepletoryLib.Caching.Abstractions (>= 1.0.0)
- RepletoryLib.Common (>= 1.0.0)
- RepletoryLib.Messaging.Abstractions (>= 1.0.0)
- RepletoryLib.Utilities.DateAndTime (>= 1.0.0)
- xunit (>= 2.9.3)
- xunit.runner.visualstudio (>= 2.8.2)
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 |