🏢 Microservices Testing Guide
Test complex microservice architectures with confidence. Accelergreat enables you to run multiple services together, test service-to-service communication, and debug across your entire distributed system.
Advanced Feature: Microservices testing showcases Accelergreat's powerful capabilities for complex integration scenarios.
🎯 What You'll Learn
- 🔧 Multi-Service Setup - Run multiple APIs together
- 🌐 Service Communication - Test API-to-API calls
- 🔍 Cross-Service Debugging - Debug across your entire system
- 🚀 Advanced Scenarios - Authentication, message queues, event sourcing
🔧 Setup Guide
1. Project References
Add references to all your microservice projects:
<Project Sdk="Microsoft.NET.Sdk">
<ItemGroup>
<ProjectReference Include="..\..\src\OrderService\OrderService.csproj" />
<ProjectReference Include="..\..\src\PaymentService\PaymentService.csproj" />
<ProjectReference Include="..\..\src\InventoryService\InventoryService.csproj" />
<ProjectReference Include="..\..\src\NotificationService\NotificationService.csproj" />
</ItemGroup>
</Project>
2. Aliases for Minimal APIs (.NET 6+)
For projects using minimal APIs, add aliases to avoid naming conflicts:
<Project Sdk="Microsoft.NET.Sdk">
<ItemGroup>
<ProjectReference Include="..\..\src\OrderService\OrderService.csproj" Aliases="OrderService" />
<ProjectReference Include="..\..\src\PaymentService\PaymentService.csproj" Aliases="PaymentService" />
<ProjectReference Include="..\..\src\InventoryService\InventoryService.csproj" Aliases="InventoryService" />
</ItemGroup>
</Project>
3. Component Creation
Create KestrelWebAppComponent
for each service:
// Order Service Component
extern alias OrderService;
using OrderProgram = OrderService::Program;
public class OrderServiceComponent : KestrelWebAppComponent<OrderProgram>
{
protected override void BuildConfiguration(
IConfigurationBuilder configurationBuilder,
IReadOnlyAccelergreatEnvironmentPipelineData environmentData)
{
// Database connection
configurationBuilder.AddEntityFrameworkDatabaseConnectionString<OrderDbContext>(
"DefaultConnection", environmentData);
// Other service URLs
var paymentServiceUrl = environmentData.GetKestrelWebAppHttpBaseAddress<PaymentService.Program>();
var inventoryServiceUrl = environmentData.GetKestrelWebAppHttpBaseAddress<InventoryService.Program>();
configurationBuilder.AddInMemoryCollection(new[]
{
new KeyValuePair<string, string>("PaymentService:BaseUrl", paymentServiceUrl),
new KeyValuePair<string, string>("InventoryService:BaseUrl", inventoryServiceUrl)
});
}
}
// Payment Service Component
extern alias PaymentService;
using PaymentProgram = PaymentService::Program;
public class PaymentServiceComponent : KestrelWebAppComponent<PaymentProgram>
{
protected override void BuildConfiguration(
IConfigurationBuilder configurationBuilder,
IReadOnlyAccelergreatEnvironmentPipelineData environmentData)
{
configurationBuilder.AddEntityFrameworkDatabaseConnectionString<PaymentDbContext>(
"DefaultConnection", environmentData);
// External payment provider (mock)
configurationBuilder.AddInMemoryCollection(new[]
{
new KeyValuePair<string, string>("PaymentProvider:ApiKey", "test-key-123"),
new KeyValuePair<string, string>("PaymentProvider:BaseUrl", "https://api.mockpayment.com")
});
}
}
// Inventory Service Component
extern alias InventoryService;
using InventoryProgram = InventoryService::Program;
public class InventoryServiceComponent : KestrelWebAppComponent<InventoryProgram>
{
protected override void BuildConfiguration(
IConfigurationBuilder configurationBuilder,
IReadOnlyAccelergreatEnvironmentPipelineData environmentData)
{
configurationBuilder.AddEntityFrameworkDatabaseConnectionString<InventoryDbContext>(
"DefaultConnection", environmentData);
}
}
4. Startup Configuration
public class Startup : IAccelergreatStartup
{
public void Configure(IAccelergreatBuilder builder)
{
// Database first
builder.AddAccelergreatComponent<DatabaseComponent>();
// Services in dependency order
builder.AddAccelergreatComponent<InventoryServiceComponent>();
builder.AddAccelergreatComponent<PaymentServiceComponent>();
builder.AddAccelergreatComponent<OrderServiceComponent>(); // Depends on others
// Optional: Notification service
builder.AddAccelergreatComponent<NotificationServiceComponent>();
}
}
🎨 Advanced Scenarios
Authentication & Authorization
public class AuthServiceComponent : KestrelWebAppComponent<AuthService.Program>
{
protected override void BuildConfiguration(
IConfigurationBuilder configurationBuilder,
IReadOnlyAccelergreatEnvironmentPipelineData environmentData)
{
configurationBuilder.AddInMemoryCollection(new[]
{
new KeyValuePair<string, string>("JWT:SecretKey", "super-secret-test-key-1234567890"),
new KeyValuePair<string, string>("JWT:Issuer", "TestIssuer"),
new KeyValuePair<string, string>("JWT:Audience", "TestAudience")
});
}
}
public class OrderServiceComponent : KestrelWebAppComponent<OrderService.Program>
{
protected override void BuildConfiguration(
IConfigurationBuilder configurationBuilder,
IReadOnlyAccelergreatEnvironmentPipelineData environmentData)
{
// Get auth service URL
var authServiceUrl = environmentData.GetKestrelWebAppHttpBaseAddress<AuthService.Program>();
configurationBuilder.AddInMemoryCollection(new[]
{
new KeyValuePair<string, string>("Authentication:Authority", authServiceUrl),
new KeyValuePair<string, string>("Authentication:Audience", "TestAudience")
});
}
}
Message Queues & Event Sourcing
public class MessageQueueComponent : IAccelergreatComponent
{
private readonly InMemoryMessageQueue _messageQueue = new();
public async Task InitializeAsync(IAccelergreatEnvironmentPipelineData environmentData)
{
// Share message queue across services
environmentData.Add("MessageQueue", _messageQueue);
// Configure message handlers
_messageQueue.Subscribe<OrderPlacedEvent>(HandleOrderPlaced);
_messageQueue.Subscribe<PaymentProcessedEvent>(HandlePaymentProcessed);
}
public Task ResetAsync()
{
_messageQueue.Clear();
return Task.CompletedTask;
}
private Task HandleOrderPlaced(OrderPlacedEvent @event)
{
// Test event handling
return Task.CompletedTask;
}
public ValueTask DisposeAsync() => ValueTask.CompletedTask;
}
public class OrderServiceComponent : KestrelWebAppComponent<OrderService.Program>
{
protected override void BuildConfiguration(
IConfigurationBuilder configurationBuilder,
IReadOnlyAccelergreatEnvironmentPipelineData environmentData)
{
var messageQueue = environmentData.Get<InMemoryMessageQueue>("MessageQueue");
configurationBuilder.AddInMemoryCollection(new[]
{
new KeyValuePair<string, string>("MessageQueue:Type", "InMemory")
});
}
protected override void ConfigureWebHost(
IWebHostBuilder builder,
IConfiguration configuration,
IReadOnlyAccelergreatEnvironmentPipelineData environmentData)
{
builder.ConfigureServices(services =>
{
var messageQueue = environmentData.Get<InMemoryMessageQueue>("MessageQueue");
services.AddSingleton(messageQueue);
});
}
}
API Gateway Integration
public class ApiGatewayComponent : KestrelWebAppComponent<ApiGateway.Program>
{
protected override void BuildConfiguration(
IConfigurationBuilder configurationBuilder,
IReadOnlyAccelergreatEnvironmentPipelineData environmentData)
{
// Configure downstream services
var orderServiceUrl = environmentData.GetKestrelWebAppHttpBaseAddress<OrderService.Program>();
var paymentServiceUrl = environmentData.GetKestrelWebAppHttpBaseAddress<PaymentService.Program>();
var inventoryServiceUrl = environmentData.GetKestrelWebAppHttpBaseAddress<InventoryService.Program>();
configurationBuilder.AddInMemoryCollection(new[]
{
new KeyValuePair<string, string>("DownstreamServices:OrderService", orderServiceUrl),
new KeyValuePair<string, string>("DownstreamServices:PaymentService", paymentServiceUrl),
new KeyValuePair<string, string>("DownstreamServices:InventoryService", inventoryServiceUrl)
});
}
}
🔍 Testing Patterns
End-to-End Workflow Testing
[Fact]
public async Task CompleteOrderWorkflow_ShouldUpdateAllServices()
{
// Arrange
var gatewayClient = GetComponent<ApiGatewayComponent>().CreateClient();
var orderDb = GetComponent<OrderDatabaseComponent>().DbContextFactory.NewDbContext();
var inventoryDb = GetComponent<InventoryDatabaseComponent>().DbContextFactory.NewDbContext();
// Setup test data
var product = new Product { Id = 1, Name = "Test Product", Price = 99.99m };
var inventory = new InventoryItem { ProductId = 1, Quantity = 10 };
inventoryDb.Products.Add(product);
inventoryDb.InventoryItems.Add(inventory);
await inventoryDb.SaveChangesAsync();
// Act - Place order through gateway
var response = await gatewayClient.PostAsJsonAsync("/api/orders", new
{
ProductId = 1,
Quantity = 2,
CustomerId = 123
});
// Assert - Check all services were updated
response.Should().BeSuccessful();
var order = await response.Content.ReadFromJsonAsync<Order>();
order.Should().NotBeNull();
order.Status.Should().Be(OrderStatus.Confirmed);
// Verify order was saved
var savedOrder = await orderDb.Orders.FindAsync(order.Id);
savedOrder.Should().NotBeNull();
// Verify inventory was updated
var updatedInventory = await inventoryDb.InventoryItems.FindAsync(1);
updatedInventory.Quantity.Should().Be(8);
// Verify payment was processed
var paymentClient = GetComponent<PaymentServiceComponent>().CreateClient();
var paymentResponse = await paymentClient.GetAsync($"/payments/order/{order.Id}");
paymentResponse.Should().BeSuccessful();
}
Service Communication Testing
[Fact]
public async Task OrderService_ShouldCallPaymentService_WhenOrderPlaced()
{
// Arrange
var orderClient = GetComponent<OrderServiceComponent>().CreateClient();
var paymentClient = GetComponent<PaymentServiceComponent>().CreateClient();
// Mock payment service endpoint
var mockPaymentHandler = new MockPaymentHandler();
var paymentService = GetComponent<PaymentServiceComponent>();
paymentService.ConfigureTestServices(services =>
{
services.AddSingleton(mockPaymentHandler);
});
// Act
var orderResponse = await orderClient.PostAsJsonAsync("/orders", new
{
ProductId = 1,
Quantity = 1,
CustomerId = 123,
Amount = 99.99m
});
// Assert
orderResponse.Should().BeSuccessful();
// Verify payment service was called
mockPaymentHandler.PaymentRequests.Should().HaveCount(1);
mockPaymentHandler.PaymentRequests[0].Amount.Should().Be(99.99m);
}
Circuit Breaker & Resilience Testing
[Fact]
public async Task OrderService_ShouldHandlePaymentServiceFailure()
{
// Arrange
var orderClient = GetComponent<OrderServiceComponent>().CreateClient();
// Simulate payment service failure
var paymentService = GetComponent<PaymentServiceComponent>();
paymentService.SimulateFailure(HttpStatusCode.ServiceUnavailable);
// Act
var orderResponse = await orderClient.PostAsJsonAsync("/orders", new
{
ProductId = 1,
Quantity = 1,
CustomerId = 123,
Amount = 99.99m
});
// Assert - Order should be created but marked as pending
orderResponse.Should().BeSuccessful();
var order = await orderResponse.Content.ReadFromJsonAsync<Order>();
order.Status.Should().Be(OrderStatus.PaymentPending);
}
🐛 Debugging Across Services
Visual Studio Debugging
[Fact]
public async Task DebugAcrossServices()
{
// Set breakpoints in any service!
var orderClient = GetComponent<OrderServiceComponent>().CreateClient();
var paymentClient = GetComponent<PaymentServiceComponent>().CreateClient();
// Breakpoint here
var order = await orderClient.PostAsJsonAsync("/orders", new { ... });
// Step through OrderService code
// Step through PaymentService code
// Debug the entire workflow!
}
Logging & Diagnostics
public class OrderServiceComponent : KestrelWebAppComponent<OrderService.Program>
{
protected override void ConfigureWebHost(
IWebHostBuilder builder,
IConfiguration configuration,
IReadOnlyAccelergreatEnvironmentPipelineData environmentData)
{
builder.ConfigureServices(services =>
{
// Enhanced logging for debugging
services.AddLogging(config =>
{
config.AddConsole();
config.AddDebug();
config.SetMinimumLevel(LogLevel.Debug);
});
});
}
}
📊 Performance Considerations
Service Startup Optimization
public class OptimizedServiceComponent : KestrelWebAppComponent<Service.Program>
{
protected override void ConfigureWebHost(
IWebHostBuilder builder,
IConfiguration configuration,
IReadOnlyAccelergreatEnvironmentPipelineData environmentData)
{
builder.ConfigureServices(services =>
{
// Disable unnecessary services in tests
services.Configure<HealthCheckOptions>(options =>
{
options.Enabled = false;
});
// Use in-memory caching instead of Redis
services.AddMemoryCache();
// services.AddStackExchangeRedisCache(...); // Disabled for tests
});
}
}
Database Sharing
public class SharedDatabaseComponent : SqlServerEntityFrameworkDatabaseComponent<SharedDbContext>
{
public SharedDatabaseComponent(IConfiguration configuration) : base(configuration)
{
}
}
public class OrderServiceComponent : KestrelWebAppComponent<OrderService.Program>
{
protected override void BuildConfiguration(
IConfigurationBuilder configurationBuilder,
IReadOnlyAccelergreatEnvironmentPipelineData environmentData)
{
// Multiple services can share the same database
configurationBuilder.AddEntityFrameworkDatabaseConnectionString<SharedDbContext>(
"DefaultConnection", environmentData);
}
}
🎯 Best Practices
1. Service Dependency Order
public void Configure(IAccelergreatBuilder builder)
{
// ✅ Correct order - foundation services first
builder.AddAccelergreatComponent<DatabaseComponent>();
builder.AddAccelergreatComponent<CacheComponent>();
builder.AddAccelergreatComponent<MessageQueueComponent>();
// Core services
builder.AddAccelergreatComponent<AuthServiceComponent>();
builder.AddAccelergreatComponent<InventoryServiceComponent>();
builder.AddAccelergreatComponent<PaymentServiceComponent>();
// Composite services
builder.AddAccelergreatComponent<OrderServiceComponent>();
builder.AddAccelergreatComponent<NotificationServiceComponent>();
// Gateway last
builder.AddAccelergreatComponent<ApiGatewayComponent>();
}
2. Configuration Management
// ✅ Use environment data for service URLs
var paymentServiceUrl = environmentData.GetKestrelWebAppHttpBaseAddress<PaymentService.Program>();
// ❌ Don't hardcode URLs
var paymentServiceUrl = "https://localhost:5001";
3. Test Isolation
[Collection("ECommerceTests")]
public class OrderTests : AccelergreatXunitTest
{
// Tests in same collection share services
}
[Collection("ECommerceTests")]
public class PaymentTests : AccelergreatXunitTest
{
// Same service instances
}
[Collection("InventoryTests")] // Different collection = different instances
public class InventoryTests : AccelergreatXunitTest
{
// Fresh service instances
}
4. Mock External Dependencies
public class PaymentServiceComponent : KestrelWebAppComponent<PaymentService.Program>
{
protected override void BuildConfiguration(
IConfigurationBuilder configurationBuilder,
IReadOnlyAccelergreatEnvironmentPipelineData environmentData)
{
// ✅ Mock external services
configurationBuilder.AddInMemoryCollection(new[]
{
new KeyValuePair<string, string>("PaymentProvider:BaseUrl", "https://mock.payment.com"),
new KeyValuePair<string, string>("PaymentProvider:ApiKey", "test-key")
});
}
}
📚 Real-World Examples
E-Commerce Platform
// Services: OrderService, PaymentService, InventoryService, NotificationService
// Database: Shared SQL Server with separate schemas
// Communication: HTTP REST APIs
// Authentication: JWT tokens via AuthService
Event-Driven Architecture
// Services: OrderService, PaymentService, InventoryService
// Communication: Event bus (RabbitMQ/Azure Service Bus)
// Database: Event store + read models
// Patterns: CQRS, Event Sourcing
Microservices with Gateway
// Services: 10+ microservices
// Gateway: Ocelot/YARP API Gateway
// Database: Multiple databases per service
// Discovery: Service discovery with health checks
🔗 Related Resources
🎉 Community Support
Need help with complex microservices scenarios? Get support from our community:
- Discord Community - Active developer community
- GitHub Issues - Bug reports and feature requests
- Documentation - Comprehensive guides and examples
- Email Support - General questions and guidance
Contact: mail@accelergreat.net • Discord
📝 Documentation Notice: This documentation has been generated using Cursor AI to improve clarity and developer experience. While every effort has been made to proofread and ensure accuracy, if you encounter any issues or inaccuracies, please contact us at mail@accelergreat.net.
Master microservices testing with Accelergreat. Turn complex distributed systems into simple, fast, reliable tests.