Giới Thiệu
Wolverine là một thư viện nhắn tin mạnh mẽ trong hệ sinh thái .NET. Trong bài viết này, chúng ta sẽ khám phá cách sử dụng Wolverine kết hợp với Azure Service Bus để thực hiện các bài kiểm tra tích hợp (integration tests) hiệu quả. Việc sử dụng Testcontainers cho phép chúng ta xác thực các dịch vụ dựa trên thông điệp mà không cần phải triển khai toàn bộ ứng dụng hoặc thiết lập các phụ thuộc phức tạp trong quá trình phát triển.
Tại Sao Chọn Wolverine?
Wolverine được thiết kế để đơn giản hóa việc xây dựng ứng dụng nhắn tin trong .NET. Nó có khả năng tích hợp tốt với Azure Service Bus, giúp các nhà phát triển dễ dàng thực hiện các bài kiểm tra mà không cần lo ngại về việc cấu hình phức tạp.
Cấu Hình Wolverine
Tạo Ứng Dụng .NET 8 Sử Dụng Wolverine
Chúng ta sẽ bắt đầu bằng cách xây dựng một ứng dụng .NET 8 đơn giản sử dụng Wolverine để lắng nghe một chủ đề (topic) từ Azure Service Bus.
csharp
public class Program
{
public static async Task Main(string[] args)
{
var host = CreateApp(args);
await host.RunAsync();
}
public static WebApplication CreateApp(string[] args)
{
var builder = WebApplication.CreateBuilder(args);
builder.UseWolverine(opts =>
{
// Lấy chuỗi kết nối ASB từ biến môi trường hoặc cấu hình
var connectionString = Environment.GetEnvironmentVariable("AzureServiceBusConnectionString");
var azureServiceBus = opts.UseAzureServiceBus(connectionString);
azureServiceBus
.ListenToAzureServiceBusSubscription("my-subscription")
.FromTopic("my-topic");
// Lưu ý: Nếu bạn sử dụng bất kỳ tùy chọn nào sau đây, hãy đảm bảo chúng được *vô hiệu hóa* khi chạy bài kiểm tra tích hợp.
});
var services = builder.Services;
var app = builder.Build();
return app;
}
}
Xử Lý Tin Nhắn
Tiếp theo, chúng ta sẽ triển khai một bộ xử lý tin nhắn đơn giản.
csharp
using Wolverine;
public class MyMessageHandler
{
public async Task Handle(MyMessage message, IMessageContext context)
{
// Xử lý tin nhắn ...
return Task.CompletedTask;
}
}
Thiết Lập Môi Trường Kiểm Tra
Chúng ta sẽ sử dụng WebApplicationFactory<T>, cho phép chúng ta ghi đè chuỗi kết nối Azure Service Bus của ứng dụng. Dưới đây là chi tiết về cách làm điều này.
csharp
public class TestAppFactory : WebApplicationFactory<Program>
{
public string ServiceBusConnectionString { get; set; }
public IHost Host { get; private set; }
protected override IHost CreateHost(IHostBuilder builder)
{
builder
.ConfigureHostConfiguration(cfg =>
{
Environment.SetEnvironmentVariable("AzureServiceBusConnectionString", ServiceBusConnectionString);
});
Host = base.CreateHost(builder);
return Host;
}
}
Cấu Hình Azure Service Bus Emulator
Một trong những khác biệt chính khi sử dụng Azure Service Bus Emulator so với một phiên bản thực tế trên Azure là cách mà các tài nguyên (hàng đợi, chủ đề, đăng ký, v.v.) được định nghĩa.
Trong emulator, bạn phải định nghĩa tất cả các tài nguyên này trong một cấu trúc cấu hình chuyên dụng, có thể được lưu trong một tệp bên cạnh mã kiểm tra của bạn. Dưới đây là một ví dụ về tệp cấu hình.
json
{
"UserConfig": {
"Namespaces": [
{
"Name": "sbemulatorns",
"Queues": [
{
"Name": "my-queue"
}
],
"Topics": [
{
"Name": "my-topic",
"Subscriptions": [
{
"Name": "my-topic-subscription"
}
]
}
]
}
],
"Logging": {
"Type": "File"
}
}
}
Thiết Bị Kiểm Tra
Nếu bạn viết nhiều hơn một bài kiểm tra tích hợp, rất có thể bạn sẽ tạo một thiết bị kiểm tra riêng biệt. Điều này cho phép chúng ta tái sử dụng container Azure Service Bus cho nhiều trường hợp kiểm tra thông qua thuộc tính CollectionDefinition của XUnit.
csharp
[CollectionDefinition(nameof(TestFixture), DisableParallelization = true)]
public class TestCollection : ICollectionFixture<TestFixture> { }
public class TestFixture
{
public ServiceBusContainer ServiceBusContainer { get; protected set; } = null!;
public TestAppFactory AppFactory { get; protected set; } = null!;
public TestFixture()
{
var configPath = Path.Combine(AppContext.BaseDirectory, "azure-servicebus-config.json");
ServiceBusContainer = new ServiceBusBuilder()
.WithImage("mcr.microsoft.com/azure-messaging/servicebus-emulator:latest")
.WithAcceptLicenseAgreement(true)
.WithName("my-azure-service-bus-container")
.WithConfig(configPath)
.WithPortBinding(5672, false);
.Build();
await ServiceBusContainer.StartAsync();
AppFactory = new TestAppFactory
{
ServiceBusConnectionString = ServiceBusContainer.GetConnectionString()
};
}
}
Bài Kiểm Tra
Cuối cùng, chúng ta hãy xem những bài kiểm tra mà chúng ta có thể thực hiện với Wolverine.
csharp
[Collection(nameof(TestFixture))]
public class MyTests
{
private readonly TestFixture _fixture;
private readonly TestAppFactory _app;
public MyTests(TestFixture fixture)
{
_fixture = fixture;
_app = _fixture.AppFactory;
}
[Fact]
public async Task Handles_my_message()
{
// Arrange
var message = new MyMessage();
// Act
await _app.Host
.TrackActivity()
.Timeout(5.Seconds())
.WaitForMessageToBeReceivedAt<MyMessage>(_app.Host)
.PublishMessageAndWaitAsync(message);
// Assert
// Logic xác minh khác ở đây
}
}
Kết Luận
Mặc dù có vẻ như việc thiết lập ban đầu có thể khá phức tạp, nhưng đây chủ yếu chỉ là một lần. Điều tuyệt vời là phần lớn công việc này chỉ cần thực hiện một lần. Việc thêm các bài kiểm tra từ đây trở đi sẽ trở nên dễ dàng hơn.
Hãy bắt đầu kiểm tra ngay hôm nay và tận hưởng những lợi ích mà Wolverine và Azure Service Bus mang lại cho quy trình phát triển của bạn!