Zircon.Test
1.0.0
dotnet add package Zircon.Test --version 1.0.0
NuGet\Install-Package Zircon.Test -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="Zircon.Test" Version="1.0.0" />
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Zircon.Test" Version="1.0.0" />
<PackageReference Include="Zircon.Test" />
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 Zircon.Test --version 1.0.0
The NuGet Team does not provide support for this client. Please contact its maintainers for support.
#r "nuget: Zircon.Test, 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 Zircon.Test@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=Zircon.Test&version=1.0.0
#tool nuget:?package=Zircon.Test&version=1.0.0
The NuGet Team does not provide support for this client. Please contact its maintainers for support.
Zircon.Test
Testing utilities with AutoFixture and AutoMoq integration for streamlined unit testing using the Fixture/Builder pattern.
Installation
dotnet add package Zircon.Test
Features
AutoMoqFixture<TSut>
base class for test fixtures- Automatic dependency mocking with AutoMoq
- Lazy SUT (System Under Test) creation
- Fluent builder pattern for test setup
- Mock retrieval with
GetMock<T>()
The Fixture Pattern
The fixture pattern separates test setup from test logic, making tests more readable and maintainable.
1. Create a Test Fixture
using Zircon.Test;
using Moq;
public class ProductServiceFixture : AutoMoqFixture<ProductService>
{
// Access mocks for dependencies
public Mock<IProductRepository> RepositoryMock => GetMock<IProductRepository>();
public Mock<ILogger<ProductService>> LoggerMock => GetMock<ILogger<ProductService>>();
// Builder method for setting up an existing product
public ProductServiceFixture WithExistingProduct(Product product)
{
RepositoryMock
.Setup(x => x.GetByIdAsync(product.Id))
.ReturnsAsync(product);
return this;
}
// Builder method for product not found scenario
public ProductServiceFixture WithProductNotFound(Guid productId)
{
RepositoryMock
.Setup(x => x.GetByIdAsync(productId))
.ReturnsAsync((Product?)null);
return this;
}
// Builder method for multiple products
public ProductServiceFixture WithMultipleProducts(params Product[] products)
{
foreach (var product in products)
{
WithExistingProduct(product);
}
return this;
}
}
2. Write Clean Tests
public class ProductServiceTests
{
[Fact]
public async Task GetProduct_WhenProductExists_ReturnsProduct()
{
// Arrange
var product = new Product { Id = Guid.NewGuid(), Name = "Test Product", Price = 99.99m };
var fixture = new ProductServiceFixture()
.WithExistingProduct(product);
// Act
var result = await fixture.Sut.GetProductAsync(product.Id);
// Assert
result.Should().NotBeNull();
result.Should().BeEquivalentTo(product);
}
[Fact]
public async Task GetProduct_WhenNotFound_ReturnsNull()
{
// Arrange
var productId = Guid.NewGuid();
var fixture = new ProductServiceFixture()
.WithProductNotFound(productId);
// Act
var result = await fixture.Sut.GetProductAsync(productId);
// Assert
result.Should().BeNull();
}
}
Complex Example with Multiple Dependencies
public class OrderServiceFixture : AutoMoqFixture<OrderService>
{
public Mock<IOrderRepository> OrderRepoMock => GetMock<IOrderRepository>();
public Mock<IProductService> ProductServiceMock => GetMock<IProductService>();
public Mock<IPaymentService> PaymentServiceMock => GetMock<IPaymentService>();
public Mock<IEmailService> EmailServiceMock => GetMock<IEmailService>();
public OrderServiceFixture WithSuccessfulPayment()
{
PaymentServiceMock
.Setup(x => x.ProcessPaymentAsync(It.IsAny<decimal>(), It.IsAny<string>()))
.ReturnsAsync(new PaymentResult { Success = true, TransactionId = "TXN123" });
return this;
}
public OrderServiceFixture WithFailedPayment(string reason = "Insufficient funds")
{
PaymentServiceMock
.Setup(x => x.ProcessPaymentAsync(It.IsAny<decimal>(), It.IsAny<string>()))
.ReturnsAsync(new PaymentResult { Success = false, Error = reason });
return this;
}
public OrderServiceFixture WithProductsInStock(params Product[] products)
{
foreach (var product in products)
{
ProductServiceMock
.Setup(x => x.GetProductAsync(product.Id))
.ReturnsAsync(product);
ProductServiceMock
.Setup(x => x.IsInStockAsync(product.Id))
.ReturnsAsync(true);
}
return this;
}
}
// Using the fixture in tests
[Fact]
public async Task PlaceOrder_WithValidOrder_ProcessesSuccessfully()
{
// Arrange - Clean, readable setup
var products = new[]
{
new Product { Id = Guid.NewGuid(), Name = "Product 1", Price = 50m },
new Product { Id = Guid.NewGuid(), Name = "Product 2", Price = 30m }
};
var fixture = new OrderServiceFixture()
.WithProductsInStock(products)
.WithSuccessfulPayment();
var order = new Order
{
Items = products.Select(p => new OrderItem { ProductId = p.Id, Quantity = 1 }).ToList()
};
// Act
var result = await fixture.Sut.PlaceOrderAsync(order);
// Assert
result.Success.Should().BeTrue();
result.OrderId.Should().NotBeEmpty();
// Verify interactions
fixture.PaymentServiceMock.Verify(
x => x.ProcessPaymentAsync(80m, It.IsAny<string>()),
Times.Once
);
}
Test Data Builders
Combine fixtures with builders for even cleaner tests:
public class ProductBuilder
{
private Guid _id = Guid.NewGuid();
private string _name = "Standard Product";
private decimal _price = 99.99m;
public ProductBuilder WithId(Guid id)
{
_id = id;
return this;
}
public ProductBuilder WithName(string name)
{
_name = name;
return this;
}
public ProductBuilder WithPrice(decimal price)
{
_price = price;
return this;
}
public Product Build()
{
return new Product { Id = _id, Name = _name, Price = _price };
}
// Specialized builders for common scenarios
public Product BuildPremiumProduct()
{
return new Product
{
Id = Guid.NewGuid(),
Name = "Premium Gold Package",
Price = 999.99m,
Category = "Premium"
};
}
}
// Usage
[Fact]
public async Task GetPremiumProduct_ReturnsCorrectDiscount()
{
// Arrange
var product = new ProductBuilder().BuildPremiumProduct();
var fixture = new ProductServiceFixture()
.WithExistingProduct(product);
// Act
var result = await fixture.Sut.GetProductWithDiscountAsync(product.Id);
// Assert
result.DiscountPercentage.Should().Be(20); // Premium products get 20% discount
}
Key Benefits
- Separation of Concerns: Test setup logic is separated from test assertions
- Reusability: Common scenarios can be reused across multiple tests
- Readability: Tests clearly show what's being arranged using fluent syntax
- Maintainability: Changes to setup logic only need to be made in one place
- Auto-mocking: Dependencies are automatically mocked by AutoFixture
Best Practices
- Name fixture methods clearly:
WithValidUser
,WithExpiredToken
,WithEmptyCart
- Chain multiple setups:
.WithUser(user).WithProducts(products).WithSuccessfulPayment()
- Keep fixture methods focused: Each method should set up one specific scenario
- Use
Sut
property: Access the system under test (lazy-loaded) - Verify important interactions: Use mocks to verify critical method calls
API Reference
AutoMoqFixture<TSut>
Properties:
Fixture
: The AutoFixture instance with AutoMoq customizationSut
: The system under test (automatically created with dependencies)
Methods:
GetMock<T>()
: Gets a frozen mock for the specified type
Dependencies
- AutoFixture
- AutoFixture.AutoMoq
- Moq
- xUnit (recommended test framework)
Product | Versions Compatible and additional computed target framework versions. |
---|---|
.NET | net8.0 is compatible. 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. net10.0 was computed. 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.
-
net8.0
- AutoFixture (>= 4.18.1)
- AutoFixture.AutoMoq (>= 4.18.1)
- coverlet.collector (>= 6.0.4)
- Microsoft.NET.Test.Sdk (>= 17.13.0)
- xunit (>= 2.9.3)
- xunit.runner.visualstudio (>= 3.0.2)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
Version | Downloads | Last Updated |
---|---|---|
1.0.0 | 54 | 8/31/2025 |