ORTA
Testing Strategies
Background job'lar normal .NET metotlarıdır — bu da test edilmelerini kolaylaştırır.
Karar Rehberi
| Durum | Öneri | Örnek veya gerekçe |
|---|---|---|
| Job method logic | Uygun: Unit test (mock DI) | Mail gönderim servisini izole test et |
| Enqueue doğrulaması | Uygun: Mock IBackgroundJobClient | Controller'dan job enqueue edildiğini doğrula |
| Full pipeline | Uygun: InMemory integration | Job chain doğru sırada çalışıyor mu? |
| Cron schedule doğruluğu | Uygun: Cronos kütüphanesiyle parse test | "0 9 * * 1-5" gerçekten hafta içi mi? |
| Dashboard render test | Uygun değil: Anlamsız | UI Hangfire'a ait |
Unit Test: Job Method
public class OrderNotificationServiceTests
{
private readonly Mock<IEmailSender> _emailSender = new();
private readonly Mock<IOrderRepository> _orderRepo = new();
private readonly OrderNotificationService _sut;
public OrderNotificationServiceTests()
{
_sut = new OrderNotificationService(_emailSender.Object, _orderRepo.Object);
}
[Fact]
public async Task SendConfirmationAsync_ValidOrder_SendsEmail()
{
// Arrange
var order = new Order { Id = 1, CustomerEmail = "test@example.com", Status = OrderStatus.Paid };
_orderRepo.Setup(r => r.GetByIdAsync(1)).ReturnsAsync(order);
// Act
await _sut.SendConfirmationAsync(1);
// Assert
_emailSender.Verify(e => e.SendAsync(
"test@example.com",
It.IsAny<string>(),
It.IsAny<string>()), Times.Once);
}
[Fact]
public async Task SendConfirmationAsync_OrderNotFound_DoesNothing()
{
_orderRepo.Setup(r => r.GetByIdAsync(99)).ReturnsAsync((Order?)null);
await _sut.SendConfirmationAsync(99);
_emailSender.Verify(e => e.SendAsync(
It.IsAny<string>(), It.IsAny<string>(), It.IsAny<string>()), Times.Never);
}
}Mock IBackgroundJobClient
public class OrderControllerTests
{
private readonly Mock<IBackgroundJobClient> _jobClient = new();
private readonly Mock<IOrderService> _orderService = new();
[Fact]
public void CreateOrder_EnqueuesNotificationJob()
{
// Arrange
var controller = new OrderController(_orderService.Object, _jobClient.Object);
_orderService.Setup(s => s.Create(It.IsAny<CreateOrderRequest>())).Returns(42);
// Act
var result = controller.CreateOrder(new CreateOrderRequest());
// Assert — Enqueue çağrıldı mı?
// IBackgroundJobClient.Create(Job job, IState state) imzasını verify ediyoruz
_jobClient.Verify(c => c.Create(
It.Is<Job>(j =>
j.Type == typeof(IOrderNotificationService) &&
j.Method.Name == nameof(IOrderNotificationService.SendConfirmationAsync)),
It.IsAny<EnqueuedState>()), Times.Once);
}
[Fact]
public void CreateOrder_PassesCorrectOrderId()
{
var controller = new OrderController(_orderService.Object, _jobClient.Object);
_orderService.Setup(s => s.Create(It.IsAny<CreateOrderRequest>())).Returns(42);
controller.CreateOrder(new CreateOrderRequest());
// Argüman kontrolü
_jobClient.Verify(c => c.Create(
It.Is<Job>(j => (int)j.Args[0] == 42),
It.IsAny<EnqueuedState>()), Times.Once);
}
}Integration Test: InMemory Storage
# Gerekli paket — test projesine ekleyin
dotnet add package Hangfire.InMemorypublic class HangfireIntegrationTests : IDisposable
{
private readonly BackgroundJobServer _server;
public HangfireIntegrationTests()
{
GlobalConfiguration.Configuration.UseInMemoryStorage();
_server = new BackgroundJobServer();
}
[Fact]
public async Task Enqueue_ProcessesJobSuccessfully()
{
var completed = new ManualResetEventSlim(false);
BackgroundJob.Enqueue(() => SignalCompletion(completed));
Assert.True(completed.Wait(TimeSpan.FromSeconds(10)));
}
public static void SignalCompletion(ManualResetEventSlim signal) => signal.Set();
public void Dispose() => _server.Dispose();
}Örnek: CI pipeline'da Hangfire job'larının unit test'leri her commit'te koşar (~100ms). Integration test'ler InMemory storage ile haftalık nightly build'de çalışır. SQL Server'lı E2E test'ler sadece release branch'inde koşar.