+
[](https://github.com/metacoder-feff/FEFF.TestFixtures/actions/workflows/test.yml)
[](https://github.com/metacoder-feff/FEFF.TestFixtures/actions/workflows/release-nuget.yml)
Integrations:
-[](https://www.nuget.org/packages/FEFF.TestFixtures.XunitV3)
-[](https://www.nuget.org/packages/FEFF.TestFixtures.TUnit)
-[](https://www.nuget.org/packages/FEFF.TestFixtures.XunitV4)
+[](https://www.nuget.org/packages/FEFF.TestFixtures.XunitV3)
+[](https://www.nuget.org/packages/FEFF.TestFixtures.TUnit)
+[](https://www.nuget.org/packages/FEFF.TestFixtures.XunitV4)
Fixture libraries:
[](https://www.nuget.org/packages/FEFF.TestFixtures)
-[](https://www.nuget.org/packages/FEFF.TestFixtures.AspNetCore)
-[](https://www.nuget.org/packages/FEFF.TestFixtures.AspNetCore.EF)
-[](https://www.nuget.org/packages/FEFF.TestFixtures.AspNetCore.SignalR)
+[](https://www.nuget.org/packages/FEFF.TestFixtures.AspNetCore)
+[](https://www.nuget.org/packages/FEFF.TestFixtures.AspNetCore.EF)
+[](https://www.nuget.org/packages/FEFF.TestFixtures.AspNetCore.SignalR)
✅ Replace setup/teardown methods and test-class "Disposable pattern" with reusable **Fixtures**.
✅ Fixtures can depend on other fixtures.
diff --git a/docs/articles/overview.md b/docs/articles/overview.md
index 08d08e4..d8fb184 100644
--- a/docs/articles/overview.md
+++ b/docs/articles/overview.md
@@ -1,6 +1,8 @@
# Overview
-FEFF.TestFixtures is a testing library extension for .NET that replaces traditional setup/teardown methods or test-class "Disposable pattern" with reusable, composable fixtures.
+{width=250 height=120}
+
+FEFF.TestFixtures is a .NET testing library extension that replaces traditional setup/teardown methods or the test-class "Disposable pattern" with reusable, composable fixtures.
## What is a Fixture?
@@ -16,19 +18,19 @@ A **fixture** is a reusable component that manages resources for testing purpose
FEFF.TestFixtures aims to:
-✅ **Eliminate boilerplate** - Replace repetitive setup/teardown methods
-✅ **Enable composition** - Build complex fixtures from simpler ones
-✅ **Simplify ASP.NET Core testing** - Built-in fixtures for web applications
-✅ **Maintain isolation** - Each test gets clean, predictable state
+✅ **Eliminate boilerplate** – Replace repetitive setup/teardown methods
+✅ **Enable composition** – Build complex fixtures from simpler ones
+✅ **Simplify ASP.NET Core testing** – Built-in fixtures for web applications
+✅ **Maintain isolation** – Each test gets clean, predictable state
-Additionaly:
-✅ **Support multiple frameworks** - Works with xUnit v3 and TUnit
+Additionally:
+✅ **Support multiple frameworks** – Works with xUnit v3 and TUnit
## Key Concepts
### Fixtures
-Fixtures are classes marked with the `[Fixture]` attribute. The framework discovers and manages their lifecycle automatically.
+Fixtures are classes marked with the `[Fixture]` attribute. The framework automatically discovers and manages their lifecycle.
```csharp
[Fixture]
@@ -50,13 +52,13 @@ public class MyFixture : IDisposable
### Scopes
-The **scope** of a fixture defines its lifetime. Within a scope, each fixture is created only once (lazily on demand) and destroyed at the end of the scope. If the fixture implements Dispose() or DisposeAsync(), those methods are called.
+The **scope** of a fixture defines its lifetime. Within a scope, each fixture is created only once (lazily, on demand) and destroyed at the end of the scope. If the fixture implements `Dispose()` or `DisposeAsync()`, those methods are called.
-The available scopes are defined by the test framework used. For **Xunit Integration**, they are:
-`TestCase` , `Class`, `Collection`, `Assembly`
+The available scopes are defined by the test framework used. For **xUnit Integration**, they are:
+`TestCase`, `Class`, `Collection`, `Assembly`
For **TUnit Integration**, they are:
-`TestCase` , `Class`, `Assembly`, `Session`
+`TestCase`, `Class`, `Assembly`, `Session`
### Fixture Dependencies
@@ -110,4 +112,5 @@ Choose your path based on your needs:
| Quick setup with TUnit | [Quick Start (TUnit)](getting-started/quick-start-tunit.md) |
| Create your own fixture | [Creating Custom Fixtures](getting-started/creating-custom-fixtures.md) |
| Combine fixtures | [Fixture Dependencies](getting-started/fixture-dependencies.md) |
-| Explore builtin fixtures | [Fixture List](fixtures/list.md) |
+| Explore built-in fixtures | [Fixture List](fixtures/list.md) |
+| Learn how to simplify ASP.NET Core application testing | [Tutorial](tutorials/asp-net-core-application-testing.md) |
diff --git a/docs/articles/tutorials/asp-net-core-application-testing.md b/docs/articles/tutorials/asp-net-core-application-testing.md
index b77b70a..f563157 100644
--- a/docs/articles/tutorials/asp-net-core-application-testing.md
+++ b/docs/articles/tutorials/asp-net-core-application-testing.md
@@ -218,7 +218,7 @@ using Microsoft.Extensions.Time.Testing;
using Newtonsoft.Json.Linq;
using Xunit.v3;
-public class WeatherForecastApiTests
+public class ApiTests
{
protected FixtureSet FixtureSet { get; } =
TestContext.Current.GetFeffFixture();
@@ -409,7 +409,6 @@ public class ApiTests
}
""");
}
- #endregion
# region helpers
@@ -461,7 +460,7 @@ public class ApiTests
Execute the test from the command line:
```bash
-dotnet test --filter "FullyQualifiedName~WeatherForecastApiTests"
+dotnet test --filter "FullyQualifiedName~ApiTests"
```
The test should pass in a few seconds. Because all external factors (time, randomness, database name) are controlled by fixtures, the result is deterministic and repeatable.
@@ -499,7 +498,7 @@ You have now written integration tests that:
2. **Request the application** via an HTTP client.
3. **Inject configuration** before startup via `IAppConfigurator`.
4. **Control externalities** like time and randomness with `FakeTimeFixture` and `FakeRandomFixture`.
-5. **Isolate data** across tests using `TmpDatabaseNameFixture`.
+5. **Isolate data** across tests using `TmpDatabaseNameFixture` and `DatabaseLifecycleFixture`.
6. **Assert on persistence** by combining HTTP calls with direct `DbContext` queries.
## See Also
diff --git a/docs/docfx.json b/docs/docfx.json
index e3bcc4f..b085be2 100644
--- a/docs/docfx.json
+++ b/docs/docfx.json
@@ -36,9 +36,15 @@
"default",
"modern"
],
+ "markdownEngineProperties": {
+ "markdigExtensions": [
+ "attributes"
+ ]
+ },
"globalMetadata": {
"_appName": "FEFF.TestFixtures Library Documentation",
"_appTitle": "FEFF.TestFixtures Library Documentation",
+ "_appLogoPath": "images/logo/logo-51-docfx.svg",
"_enableSearch": true,
"pdf": false
}
diff --git a/docs/images/logo/Concept.txt b/docs/images/logo/Concept.txt
new file mode 100644
index 0000000..8e36825
--- /dev/null
+++ b/docs/images/logo/Concept.txt
@@ -0,0 +1,22 @@
+
+The logo should represent one of these key ideas:
+Interlocking / Reusable Blocks → "Fixtures" as modular components.
+
+
+1.
+Complete 2x2x2 cube structure (8 cubes total)
+4 purple cubes + 4 teal cubes in alternating pattern
+One of cubes is elevated (half-height raised) showing dynamic insertion
+2-3 green check marks in one vertical column overlapping on the right side with Front-facing orientation (perpendicular to camera)
+Professional 3D isometric view
+
+2.
+The "Interlocking Fixture Blocks"
+What it is: 3 simple, slightly overlapping rounded squares (like Lego bricks). Two are dark gray (setup), one is green (test runs). An arrow loops from the last block back to the first, indicating teardown/reset.
+Why it fits: Mirrors MyFixtureSet(F1, F2) dependencies – fixtures assembling into larger fixtures.
+Color: Dark slate (#2D333B) + Emerald green (#2DA44E – GitHub's success green).
+
+for github-repository's social media preview
+convert docs/images/logo/logo.svg
+to png with size 1280×640px
+save as logo-1280-github.png
\ No newline at end of file
diff --git a/docs/images/logo/logo-128-nuget.png b/docs/images/logo/logo-128-nuget.png
new file mode 100644
index 0000000..da8f463
Binary files /dev/null and b/docs/images/logo/logo-128-nuget.png differ
diff --git a/docs/images/logo/logo-1280-github.png b/docs/images/logo/logo-1280-github.png
new file mode 100644
index 0000000..71cd69a
Binary files /dev/null and b/docs/images/logo/logo-1280-github.png differ
diff --git a/docs/images/logo/logo-51-docfx.svg b/docs/images/logo/logo-51-docfx.svg
new file mode 100644
index 0000000..353b10b
--- /dev/null
+++ b/docs/images/logo/logo-51-docfx.svg
@@ -0,0 +1,129 @@
+
\ No newline at end of file
diff --git a/docs/images/logo/logo.svg b/docs/images/logo/logo.svg
new file mode 100644
index 0000000..9cafe01
--- /dev/null
+++ b/docs/images/logo/logo.svg
@@ -0,0 +1,129 @@
+
\ No newline at end of file
diff --git a/src/Directory.Build.props b/src/Directory.Build.props
index c09ee98..129f771 100644
--- a/src/Directory.Build.props
+++ b/src/Directory.Build.props
@@ -24,7 +24,10 @@
Reusable testing components.https://github.com/metacoder-feff/FEFF.TestFixturestesting;fixtures;FEFF;
+
README.md
+
+ logo-128-nuget.pngtruesnupkg
@@ -44,6 +47,9 @@
-->
+
+
+
diff --git a/src/FEFF.TestFixtures.AspNetCore.EF/DatabaseLifecycleFixture.cs b/src/FEFF.TestFixtures.AspNetCore.EF/DatabaseLifecycleFixture.cs
index 55c8917..4efc019 100644
--- a/src/FEFF.TestFixtures.AspNetCore.EF/DatabaseLifecycleFixture.cs
+++ b/src/FEFF.TestFixtures.AspNetCore.EF/DatabaseLifecycleFixture.cs
@@ -9,14 +9,12 @@ namespace FEFF.TestFixtures.AspNetCore.EF;
public interface IDatabaseLifecycleFixture
{
///
- /// Ensures that the database for the context exists and is created.
+ /// Gets the instance resolved from the service provider.
///
- /// A token to cancel the operation.
- /// A task representing the asynchronous operation.
///
- /// Starts the application under test if not already running.
+ /// Accessing this property starts the application under test if not already running.
///
- Task EnsureCreatedAsync(CancellationToken token);
+ DbContext LazyDbContext { get; }
}
///
@@ -29,7 +27,7 @@ public interface IDatabaseLifecycleFixture : IDatabaseLifecycleFixture
///
/// Accessing this property starts the application under test if not already running.
///
- TContext LazyDbContext { get; }
+ new TContext LazyDbContext { get; }
}
//TODO: skip options/properties + tests
@@ -55,6 +53,8 @@ public sealed class DatabaseLifecycleFixture : IAsyncDisp
///
public TContext LazyDbContext => _servicesFx.LazyServiceProvider.GetRequiredService();
+ DbContext IDatabaseLifecycleFixture.LazyDbContext => LazyDbContext;
+
///
/// Creates a new database lifecycle management fixture.
///
@@ -78,10 +78,24 @@ public async ValueTask DisposeAsync()
// This can happen when database is locked or inaccessible
// System.Console.Error.WriteLine($"[DatabaseLifecycleFixture] Warning: Failed to delete database: {ex.Message}");
}
+}
- ///
- public async Task EnsureCreatedAsync(CancellationToken token)
+///
+/// Provides extension methods for .
+///
+public static class DatabaseLifecycleFixtureExtensions
+{
+ ///
+ /// Ensures that the database for the context exists and is created.
+ ///
+ /// The database lifecycle fixture.
+ /// A token to cancel the operation.
+ /// A task representing the asynchronous operation.
+ ///
+ /// Starts the application under test if not already running.
+ ///
+ public static async Task EnsureCreatedAsync(this IDatabaseLifecycleFixture src, CancellationToken token)
{
- await LazyDbContext.Database.EnsureCreatedAsync(token).ConfigureAwait(false);
+ await src.LazyDbContext.Database.EnsureCreatedAsync(token).ConfigureAwait(false);
}
}
diff --git a/tests/Files/API/FEFF.TestFixtures.AspNetCore.EF.verified.txt b/tests/Files/API/FEFF.TestFixtures.AspNetCore.EF.verified.txt
index e1dc71a..4fad105 100644
--- a/tests/Files/API/FEFF.TestFixtures.AspNetCore.EF.verified.txt
+++ b/tests/Files/API/FEFF.TestFixtures.AspNetCore.EF.verified.txt
@@ -2,6 +2,10 @@
[assembly: System.Runtime.Versioning.TargetFramework(".NETCoreApp,Version=v10.0", FrameworkDisplayName=".NET 10.0")]
namespace FEFF.TestFixtures.AspNetCore.EF
{
+ public static class DatabaseLifecycleFixtureExtensions
+ {
+ public static System.Threading.Tasks.Task EnsureCreatedAsync(this FEFF.TestFixtures.AspNetCore.EF.IDatabaseLifecycleFixture src, System.Threading.CancellationToken token) { }
+ }
[FEFF.TestFixtures.Fixture]
public sealed class DatabaseLifecycleFixture : FEFF.TestFixtures.AspNetCore.EF.IDatabaseLifecycleFixture, FEFF.TestFixtures.AspNetCore.EF.IDatabaseLifecycleFixture, System.IAsyncDisposable
where TEntryPoint : class
@@ -10,11 +14,10 @@ namespace FEFF.TestFixtures.AspNetCore.EF
public DatabaseLifecycleFixture(FEFF.TestFixtures.AspNetCore.AppManagerFixture app, FEFF.TestFixtures.AspNetCore.AppServicesFixture services) { }
public TContext LazyDbContext { get; }
public System.Threading.Tasks.ValueTask DisposeAsync() { }
- public System.Threading.Tasks.Task EnsureCreatedAsync(System.Threading.CancellationToken token) { }
}
public interface IDatabaseLifecycleFixture
{
- System.Threading.Tasks.Task EnsureCreatedAsync(System.Threading.CancellationToken token);
+ Microsoft.EntityFrameworkCore.DbContext LazyDbContext { get; }
}
public interface IDatabaseLifecycleFixture : FEFF.TestFixtures.AspNetCore.EF.IDatabaseLifecycleFixture
where TContext : Microsoft.EntityFrameworkCore.DbContext