NotoriousTest 2.3.0-beta.9
See the version list below for details.
dotnet add package NotoriousTest --version 2.3.0-beta.9
NuGet\Install-Package NotoriousTest -Version 2.3.0-beta.9
<PackageReference Include="NotoriousTest" Version="2.3.0-beta.9" />
paket add NotoriousTest --version 2.3.0-beta.9
#r "nuget: NotoriousTest, 2.3.0-beta.9"
// Install NotoriousTest as a Cake Addin #addin nuget:?package=NotoriousTest&version=2.3.0-beta.9&prerelease // Install NotoriousTest as a Cake Tool #tool nuget:?package=NotoriousTest&version=2.3.0-beta.9&prerelease
Notorious Test provide a simple way to isolate integration tests. Based on XUnit.
Contact
Have questions, ideas, or feedback about NotoriousTests? Feel free to reach out! I'd love to hear from you. Here's how you can get in touch:
- GitHub Issues: Open an issue to report a problem, request a feature, or share an idea.
- Email: briceschumacher21@gmail.com
- LinkedIn : Brice SCHUMACHER
The discussions tabs is now opened ! Feel free to tell me if you use the package here : https://github.com/Notorious-Coding/Notorious-Test/discussions/1 !
Summary
- Support
- Features
- Motivation
- Changelog
- Getting started
- Setup
- Base functionalities
- Advanced functionalities
- Hand's On examples
Support
- Net6+
Features
- Easy share of test infrastructure.
- Easy building of test framework.
- Complete isolation of integration tests.
- Simple implementation.
- Based on XUnit.
Motivation
The goal is to provide a way to make integration tests without worrying about data collision, side effects, and infrastructure sharing.
Changelog
You can find the changelog here.
Setup
First, install NuGet. Then, install NotoriousTest from the package manager console:
PM> Install-Package NotoriousTest
Or from the .NET CLI as:
dotnet add package NotoriousTest
Base functionalities
Infrastructures
An infrastructure is a piece of hardware or software that is necessary for your app to work. For example, a SQL Server Database is an infrastructure. NotoriousTests provide a way to design your infrastructures by creating classes for each of them.
using NotoriousTest.Common.Infrastructures.Sync;
public class SQLServerDBInfrastructure : Infrastructure
{
public SQLServerDBAsyncInfrastructure(bool initialize = false) : base(initialize){}
public override void Initialize()
{
// Here you can create the database
}
public override void Reset()
{
// Here you can empty the database
}
public override void Destroy()
{
// Here you can destroy the database
}
}
Async version :
using NotoriousTest.Common.Infrastructures.Async;
// Async version
public class SQLServerDBAsyncInfrastructure : AsyncInfrastructure
{
public SQLServerDBAsyncInfrastructure(bool initialize = false) : base(initialize){}
public override Task Initialize()
{
// Here you can create the database
}
public override Task Reset()
{
// Here you can empty the database
}
public override Task Destroy()
{
// Here you can destroy the database
}
}
As you can see, an infrastructure is made of 3 main lifecycle method.
Initialize
: You can call this method to start an infrastructure or set the initialize boolean in the constructor at true.Reset
: you can call this method to reset an infrastructure. Reset mean to put the infrastructure in an empty state without recreating it from scratch (essentialy for perfomances).Destroy
: you can call this method to destroy an infrastructure,Destroy
mean to completly delete the infrastructure.
Once you made it, you can use this infrastructure as standalone in your tests :
[Fact]
public async Task Database_Creation()
{
// Dont forget to put initialize at true, so you dont have to call **Initialize**
await using (var db = new SQLServerDBAsyncInfrastructure(initialize: true))
{
// Test logic here...
}
// Disposing an infrastructure will automatically call Destroy()
}
Even if using an infrastructures in standalone can be easy, it should be a best practices to use them inside an Environment
. Let's see why and how.
Environment
We have seen how we could use an infrastructure directly within a tests, but it will become really difficult to maintain if we do this for every test and for every infrastructure.
That's why we provide this environment feature :
An environment is a collection of infrastructure drived by tests' lifecycle.
Let's create an environment :
public class SampleEnvironment : Environment
{
public override void ConfigureEnvironment()
{
// Add all your infrastructure here.
AddInfrastructure(new DatabaseInfrastructure());
}
}
Async version :
public class SampleEnvironment : AsyncEnvironment
{
public override Task ConfigureEnvironmentAsync()
{
// Add all your infrastructure here.
AddInfrastructure(new DatabaseInfrastructure());
return Task.CompletedTask;
}
}
Then, make your test class inherit from IntegrationTest
.
public class UnitTest1 : IntegrationTest<SampleEnvironment>
{
public UnitTest1(SampleEnvironment environment) : base(environment)
{
}
[Fact]
public async void MyTest()
{
// Access infrastructure by calling
SQLServerDBAsyncInfrastructure infrastructure = await CurrentEnvironment.GetInfrastructure<SQLServerDBAsyncInfrastructure>();
}
}
Async version:
public class UnitTest1 : AsyncIntegrationTest<SampleEnvironment>
{
public UnitTest1(SampleEnvironment environment) : base(environment)
{
}
[Fact]
public async Task MyTest()
{
// Access infrastructure by calling
SQLServerDBAsyncInfrastructure infrastructure = await CurrentEnvironment.GetInfrastructureAsync<SQLServerDBAsyncInfrastructure>();
}
}
Advanced functionalities
Ordering infrastructures execution
In certain contexts, the execution order of infrastructures within an environment can be crucial.
To address this, all infrastructures provide an optional Order
property. This allows specifying the order of initialization, reset, and teardown of infrastructures.
By default, infrastructures without a defined order will be prioritized and executed first.
❗ The only exception is WebApplicationInfrastructure, which will ALWAYS be executed last, as it depends on other infrastructures' configuration.
Here's an example :
public class DatabaseInfrastructure : AsyncConfiguredInfrastructure<Configuration>
{
// Use this property to order execution.
public override int? Order => 1;
public DatabaseInfrastructure(bool initialize = false): base(initialize)
{
}
public override Task Destroy()
{
return Task.CompletedTask;
}
public override Task Initialize()
{
return Task.CompletedTask;
}
public override Task Reset()
{
return Task.CompletedTask;
}
}
Advanced Control Over Infrastructure Resets
By default, infrastructures are reset between each test to ensure data isolation. However, in certain scenarios -such as multi-tenant applications where isolation is ensured by design- automatic resets may not be necessary.
With the AutoReset
option, you can disable the automatic reset for a specific infrastructure:
public class SampleEnvironment : AsyncWebEnvironment<Program, Configuration>
{
public override Task ConfigureEnvironmentAsync()
{
AddInfrastructure(new DatabaseInfrastructure()
{
AutoReset = false
});
AddWebApplication(new SampleProjectApp());
return Task.CompletedTask;
}
}
When AutoReset
is set to false
, the Reset
method of the specified infrastructure will be skipped during the test lifecycle. This can save significant time and resources in scenarios where resetting is unnecessary.
⚠️ Note: Use this option carefully. Ensure that tests are designed to avoid dependencies on leftover data unless explicitly intended.
Configuration
In some cases, you will need to handle configuration from your infrastructures, such as connection string, or secrets, etc. Notorious Tests provides a nice way to produce and consume configuration within infrastructures.
Here's how :
Configurable Infrastructures
To create a configurable infrastructure, the only thing you need to do is to inherits from ConfiguredInfrastructure or AsyncConfiguredInfrastructure.
public class DatabaseInfrastructure : ConfiguredInfrastructure<Configuration>
{
public DatabaseInfrastructure(bool initialize = false) : base(initialize)
{
}
public override int Order => 1;
public override void Destroy(){}
public override void Initialize()
{
/// Initialize sql server.
Configuration.DatabaseConfiguration = new DatabaseConfiguration()
{
ConnectionString = "Test"
};
}
public override void Reset(){}
}
As you can see, this infrastructure will produce configuration after initializing the sql server. Configuration is available as public so you can then access it when using this infrastructure.
Generic type for configuration is not mandatory, Configuration object will be a Dictionary<string, string>
public class DatabaseInfrastructure : ConfiguredInfrastructure
{
public DatabaseInfrastructure(bool initialize = false) : base(initialize)
{
}
public override int Order => 1;
public override void Destroy(){}
public override void Initialize()
{
/// Initialize sql server.
Configuration.Add("DatabaseConfiguration.ConnectionString", "Test");
}
public override void Reset(){}
}
Now, you can access your infrastructure configuration directly within a test :
[Fact]
public async Task Test2()
{
await using (var db = new DatabaseInfrastructure(initialize: true))
{
var cs = db.Configuration.DatabaseConfiguration.ConnectionString;
}
}
Configurable Environment
You could use ConfiguredInfrastructure
within Environment.
First, inherit from ConfiguredEnvironment
instead of Environment.
(from AsyncConfiguredEnvironment instead of AsyncEnvironment).
public class SampleEnvironment : ConfiguredEnvironment<Configuration>
{
public override void ConfigureEnvironment()
{
// Add all your infrastructure here.
AddInfrastructure(new DatabaseInfrastructure());
}
}
// Or without generic type
public class SampleEnvironment : ConfiguredEnvironment{
public override void ConfigureEnvironment()
{
// Add all your infrastructure here.
AddInfrastructure(new DatabaseInfrastructure());
}
}
Within any ConfiguredEnvironment
, you would use the public property EnvironmentConfiguration
to access produced configuration from infrastructures.
❗ Inside an environment, configuration object should represent the whole app configuration. It will move from infrastructures to infrastructures, and each infrastructure will edit its own part of the configuration.
Web
Within web applications, you will certainly need to add a WebApplication that work in background so your tests can call an actual API.
NotoriousTests provide everything so you donc need to scratch your head too much.
Web Application Infrastructure
First, you will need to create an WebApplication.
internal class SampleProjectApp : WebApplication<Program>{}
This is actually a WebApplicationFactory provided by .NET (See microsoft doc for more information.)
Here you can override everything you need for your app to be fully functional.
Then, let's create an WebApplicationInfrastructure and pass our WebApplication.
:information: Within a WebEnvironment, creating an infrastructure is optional. You can directly pass a WebApplication. But this can be usefull to add initialization/reset/destroy behaviors.
internal class SampleProjectWebApplicationInfrastructure : WebApplicationInfrastructure<Program, Configuration>
{
public SampleProjectWebApplicationInfrastructure(Dictionary<string, string> configuration)
: base(new SampleProjectApp())
{
}
}
// Without a generic type, configuration will be a Dictionary<string, string>.
internal class SampleProjectWebApplicationInfrastructure : WebApplicationInfrastructure<Program>
{
public SampleProjectWebApplicationInfrastructure(Dictionary<string, string> configuration)
: base(new SampleProjectApp())
{
}
}
:information: Configuration passed will be automaticaly added as configuration on your web app, making it accessible within IConfiguration object in Program.cs.
Now, within your test, you can start your WebApplicationInfrastructures like any other infrastructure, and access HttpClient:
[Fact]
public async Task Test2()
{
await using (var app = new SampleProjectWebApplicationInfrastructure())
{
HttpClient? client = app.HttpClient;
HttpResponseMessage response = await client!.GetAsync("api/weather");
Assert.True(response.IsSuccessStatusCode);
string content = await response.Content.ReadAsStringAsync();
}
}
Web Environment
WebApplication or WebApplicationInfrastructure can be used within WebEnvironment.
public class SampleEnvironment : AsyncWebEnvironment<Program, Configuration>
{
public override Task ConfigureEnvironmentAsync()
{
AddInfrastructure(new DatabaseInfrastructure());
AddWebApplication(new SampleProjectApp());
// OR
AddWebApplication(new SampleProjectWebApplicationInfrastructure());
return Task.CompletedTask;
}
}
Your web application will start automatically at the start of a test campaign, and configuration produced by infrastructures will automaticaly be added as an InMemoryCollection to your WebApplication.
Then, in your test, you can use GetWebApplication to access the HttpClient :
[Fact]
public async Task Test2()
{
HttpClient? client = (await CurrentEnvironment.GetWebApplication()).HttpClient;
HttpResponseMessage response = await client!.GetAsync("api/weather");
Assert.True(response.IsSuccessStatusCode);
string content = await response.Content.ReadAsStringAsync();
}
Nice ! Good job, now, your integration test are isolated from each other.
TestContainers
NotoriousTest.TestContainers is now available as a separate package.
Install NotoriousTest from the package manager console:
PM> Install-Package NotoriousTest.TestContainers
Or from the .NET CLI as:
dotnet add package NotoriousTest.TestContainers
This package provides classes that automatically start and stop the container at the beginning and end of the test campaign! It introduces three new classes:
DockerContainerAsyncInfrastructure<TContainer>
: Standard infrastructure.ConfiguredDockerContainerAsyncInfrastructure<TContainer>
: Infrastructure handling configuration as a dictionary.ConfiguredDockerContainerAsyncInfrastructure<TContainer, TConfiguration>
: Infrastructure handling a configuration object.
❗ Since
TestContainers
doesn't support synchronous code, theses classes are only available in anAsyncEnvironment
.
Here's an example :
public class SqlServerContainerInfrastructure : DockerContainerAsyncInfrastructure<GenericContainer>
{
public override Container {get; init;} = new MsSqlBuild().Build();
public SampleDockerContainer(bool initialize = false) : base(initialize)
{
}
public override Task Reset()
{
return Task.CompletedTask;
}
}
Hands-On Examples
Get started quickly with practical examples available in the Samples folder. These examples demonstrate how to set up and use NotoriousTests for real-world scenarios.
What's included:
- SqlServerInfrastructures.cs
Learn how to manage your SQL Server database using Respawn, TestContainers and plain SQL for creating, destroying, and resetting your database seamlessly. - TestWebApplication.cs
See how to configure a WebApplicationFactory with in-memory configuration for fast and isolated tests. - TestEnvironment
Understand how to set up environments to manage multiple infrastructures effortlessly. - SampleTests.cs
Dive into this file to see how to access infrastructures and use them in your tests. - Program.cs
Explore how the SqlServerInfrastructure generates configuration for the Web Application.
Other nugets i'm working on
- NotoriousClient : Notorious Client is meant to simplify the sending of HTTP requests through a fluent builder and an infinitely extensible client system.
- NotoriousModules : Notorious Modules provide a simple way to separate monolith into standalone modules.
Product | Versions Compatible and additional computed target framework versions. |
---|---|
.NET | net6.0 is compatible. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 was computed. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. net8.0 was computed. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 was computed. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. |
-
net6.0
- Microsoft.AspNetCore.Mvc.Testing (>= 6.0.22)
- xunit (>= 2.5.0)
NuGet packages (1)
Showing the top 1 NuGet packages that depend on NotoriousTest:
Package | Downloads |
---|---|
NotoriousTest.TestContainers
A TestContainers integration with NotoriousTest. |
GitHub repositories
This package is not used by any popular GitHub repositories.
Version | Downloads | Last updated |
---|---|---|
3.0.0-beta.28 | 51 | 2/22/2025 |
2.3.0 | 152 | 2/10/2025 |
2.3.0-beta.25 | 42 | 2/22/2025 |
2.3.0-beta.23 | 53 | 2/14/2025 |
2.3.0-beta.20 | 57 | 2/12/2025 |
2.3.0-beta.18 | 53 | 2/10/2025 |
2.3.0-beta.16 | 53 | 2/9/2025 |
2.3.0-beta.14 | 54 | 2/9/2025 |
2.3.0-beta.9 | 57 | 2/9/2025 |
2.2.0 | 85 | 2/9/2025 |
2.2.0-beta.7 | 50 | 2/9/2025 |
2.2.0-beta.5 | 49 | 2/9/2025 |
2.2.0-beta.4 | 56 | 2/9/2025 |
2.2.0-beta.2 | 51 | 2/9/2025 |
2.1.0 | 115 | 2/2/2025 |
2.0.0 | 124 | 9/4/2024 |
1.3.4 | 137 | 5/5/2024 |
1.3.3 | 127 | 5/5/2024 |
1.3.2 | 125 | 5/5/2024 |
1.2.1 | 163 | 1/17/2024 |
1.2.0 | 167 | 10/3/2023 |
1.1.0 | 133 | 9/28/2023 |
1.0.0 | 146 | 9/19/2023 |