A utility library for convenient work with xUnit v3.
Designed to speed up writing parameterized tests and to simplify preparing mocks in DI containers.
Key features
- Attribute
JsonFileDataAttribute— load data forTheoryfrom a JSON file (multiple formats, sections). - Attribute
CustomAutoDataAttribute— ready-made configuration forAutoFixture+AutoMoq(includingConfigureMembersand recursion behavior). - Extension
MockExtension.AddMocks— bulk registration ofMoqmocks intoIServiceCollection. - Helper generator
GenerateTestDataExtensionand modelTestData— support for deserializing JSON into parameter sets up to 15 arguments. - Supported targets:
net8.0,net9.0,net10.0.
JsonFileDataAttribute
- Constructor:
JsonFileDataAttribute(string filePath, bool simpleTypeJson = false, string? sectionKey = null) - Behavior:
- Checks that the file exists.
- If
sectionKeyis specified, extracts the corresponding JSON section (top-level key). - Supports two JSON formats:
- "Complex" — an array of objects with fields
P1,P2, ... (matches theTestDatamodels). - "Simple" (
simpleTypeJson = true) — an array of arrays or an array of strings/numbers, where each element of an inner array corresponds to a test parameter.
- "Complex" — an array of objects with fields
- Limitation: up to 15 parameters (the test-case generation logic is implemented for 1..15 parameters).
- Examples: Complex data format (recommended):
[
{
"P1": 1,
"P2": "a",
"P3": true
},
{
"P1": 2,
"P2": "b",
"P3": false
}
]Simple types format (simpleTypeJson = true):
[
[1, "a", true],
[2, "b", false]
]Usage in tests:
[Theory, JsonFileData("testdata.json")]
public void MyTest(int a, string b, bool flag)
{
// ...
} [Theory, JsonFileData("simple.json", simpleTypeJson: true)]
public void SimpleTest(int a, string b)
{
// ...
} [Theory, JsonFileData("config.json", sectionKey: "cases")]
public void SectionedTest(int x, int y)
{
// ...
}CustomAutoDataAttribute
- A simplified attribute for use with
AutoFixture+AutoMoq. - Configuration:
- Adds
AutoMoqCustomizationwithConfigureMembers = true. - Removes
ThrowingRecursionBehaviorand addsOmitOnRecursionBehaviorto safely generate object graphs.
- Adds
- Example:
[Theory, CustomAutoData]
public void AutoFixtureTest(MyService sut, int n)
{
Assert.NotNull(sut);
}MockExtension.AddMocks
- An extension for
IServiceCollection: for each providedTypeit registers:Mock<T>as scoped,T(mock.Object) as scoped.
- Removes existing registrations for the type before adding the mock.
- Example:
var services = new ServiceCollection();
services.AddMocks(typeof(IMyService), typeof(IOtherService));or with generics (implemented via reflection for each type in the code).
License
- MIT
A short guide on using helper utilities for integration testing ASP.NET Core applications.
The XUnit3Helper.Integration project provides primitives to run a test WebApplication with a real Kestrel server and conveniences for controller testing:
- Test application factory with Kestrel —
BaseWebApplicationFactory, - Base class for controller tests —
BaseControllerTests.
The goal is to simplify starting a test application on a random free port, injecting startup modules, and registering controllers from a specific assembly.
- Create a factory by inheriting from
BaseWebApplicationFactory<TYourStartupModule>:- implement
ServerKey(Guid),ControllersAssembly(Assembly), and overrideEnvironmentandServiceTypeForMockif needed.
- implement
- Implement
TYourStartupModule : BaseStartupModulewith a constructor(IWebHostEnvironment, ConfigurationManager). - In your test, inherit from
BaseControllerTests<TYourStartupModule, TYourFactory>or use the factory/fixture manually and callCreateClient().
Important: CreateStartupModule creates the startup module instance using reflection — ensure your startup module contains a constructor with the required signature.
This package is required by the XUnit3Helper.Integration. It contains an abstract startup module which you should use as a base for implementing your Web API.
Example — concise constructor syntax:
public sealed class Startup(
IWebHostEnvironment environment,
ConfigurationManager configurationManager)
: BaseStartupModule(environment, configurationManager)
{
}Or using an explicit constructor that calls the base:
public sealed class Startup
: BaseStartupModule
{
public Startup(
IWebHostEnvironment environment,
ConfigurationManager configurationManager)
: base(environment, configurationManager)
{
}
}You must also implement these methods:
- ConfigureConfigurationInternal
protected abstract IConfiguration ConfigureConfigurationInternal(
IWebHostEnvironment environment,
ConfigurationManager configurationManager);Example:
protected override IConfiguration ConfigureConfigurationInternal(
IWebHostEnvironment environment,
ConfigurationManager configurationManager)
{
return configurationManager
//Set the application content root path
.SetBasePath(environment.ContentRootPath)
//Add appsettings file
.AddJsonFile("appsettings.json")
//Add environment-specific appsettings file (optional)
.AddJsonFile($"appsettings.{environment.EnvironmentName}.json", true)
//Add environment variables
.AddEnvironmentVariables()
.Build();
}- ConfigureServices
public override IServiceCollection ConfigureServices(IServiceCollection services);Example:
public override IServiceCollection ConfigureServices(IServiceCollection services)
{
services.AddCors();
services.AddControllers();
services.AddEndpointsApiExplorer();
services.AddSwaggerGen();
return services;
}- Configure
public override IApplicationBuilder Configure(IApplicationBuilder app);Example:
public override IApplicationBuilder Configure(IApplicationBuilder app)
{
app.UseRouting();
app.UseCors(policy => policy
.AllowAnyOrigin()
.AllowAnyHeader()
.AllowAnyMethod());
if (environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}
app.UseHttpsRedirection();
app.UseAuthorization();
app.UseAuthorization();
app.UseEndpoints(configure => configure.MapControllers());
return app;
}As a result, your Program.cs will look like this:
var builder = WebApplication.CreateBuilder(args);
var startup = new Startup(builder.Environment, builder.Configuration);
startup.ConfigureServices(builder.Services);
var applicationBuilder = builder.Build();
startup.Configure(applicationBuilder);
await applicationBuilder.RunAsync();