Skip to content

Commit 7e01968

Browse files
fixing transaction management unit test problem
1 parent d399c5b commit 7e01968

7 files changed

Lines changed: 90 additions & 11 deletions

File tree

ECommerce.BusinessEvents.Tests/Services/EventTrackingServiceTests.cs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
using Moq;
77
using ECommerce.Contracts.DTOs;
88
using ECommerce.Contracts.Interfaces;
9+
using ECommerce.BusinessEvents.Infrastructure;
910

1011
namespace ECommerce.BusinessEvents.Tests.Services
1112
{
@@ -15,6 +16,7 @@ public class EventTrackingServiceTests : IDisposable
1516
private readonly SchemaRegistryService _schemaRegistry;
1617
private readonly Mock<IJsonSchemaValidator> _schemaValidatorMock;
1718
private readonly EventTrackingService _eventTracker;
19+
private readonly ITransactionManager _transactionManager;
1820

1921
public EventTrackingServiceTests()
2022
{
@@ -26,7 +28,8 @@ public EventTrackingServiceTests()
2628
_schemaRegistry = new SchemaRegistryService(_context);
2729
_schemaValidatorMock = new Mock<IJsonSchemaValidator>();
2830
var loggerMock = new Mock<Microsoft.Extensions.Logging.ILogger<EventTrackingService>>();
29-
_eventTracker = new EventTrackingService(_context, _schemaRegistry, _schemaValidatorMock.Object, loggerMock.Object);
31+
_transactionManager = new NoOpTransactionManager();
32+
_eventTracker = new EventTrackingService(_context, _schemaRegistry, _schemaValidatorMock.Object, loggerMock.Object, _transactionManager);
3033

3134
InitializeTestSchema().Wait();
3235
}

ECommerce.BusinessEvents/BusinessEventsModule.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
using ECommerce.BusinessEvents.Infrastructure;
12
using ECommerce.BusinessEvents.Infrastructure.Validators;
23
using ECommerce.BusinessEvents.Persistence;
34
using ECommerce.BusinessEvents.Services;
@@ -39,6 +40,11 @@ public static IServiceCollection AddBusinessEventsModule(this IServiceCollection
3940

4041
// Register SchemaRegistryService
4142
services.AddScoped<SchemaRegistryService>();
43+
services.AddScoped<ITransactionManager, EfCoreTransactionManager>(sp =>
44+
{
45+
var dbContext = sp.GetRequiredService<BusinessEventDbContext>();
46+
return new EfCoreTransactionManager(dbContext);
47+
});
4248
services.AddScoped<IBusinessEventService, EventTrackingService>();
4349
services.AddScoped<IJsonSchemaValidator, JsonSchemaValidator>();
4450
services.AddScoped<IEventRetrievalService>(sp =>
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
using Microsoft.EntityFrameworkCore;
2+
using Microsoft.EntityFrameworkCore.Storage;
3+
4+
namespace ECommerce.BusinessEvents.Infrastructure
5+
{
6+
public class EfCoreTransactionManager : ITransactionManager
7+
{
8+
private readonly DbContext _dbContext;
9+
private IDbContextTransaction? _transaction;
10+
11+
public EfCoreTransactionManager(DbContext dbContext)
12+
{
13+
_dbContext = dbContext;
14+
}
15+
16+
public async Task BeginTransactionAsync()
17+
{
18+
_transaction = await _dbContext.Database.BeginTransactionAsync();
19+
}
20+
21+
public async Task CommitAsync()
22+
{
23+
if (_transaction != null)
24+
await _transaction.CommitAsync();
25+
}
26+
27+
public async Task RollbackAsync()
28+
{
29+
if (_transaction != null)
30+
await _transaction.RollbackAsync();
31+
}
32+
33+
public async ValueTask DisposeAsync()
34+
{
35+
if (_transaction != null)
36+
await _transaction.DisposeAsync();
37+
}
38+
}
39+
}
40+
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
using System;
2+
using System.Threading.Tasks;
3+
4+
namespace ECommerce.BusinessEvents.Infrastructure
5+
{
6+
public interface ITransactionManager : IAsyncDisposable
7+
{
8+
Task BeginTransactionAsync();
9+
Task CommitAsync();
10+
Task RollbackAsync();
11+
}
12+
}
13+
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
using System;
2+
using System.Threading.Tasks;
3+
4+
namespace ECommerce.BusinessEvents.Infrastructure
5+
{
6+
public class NoOpTransactionManager : ITransactionManager
7+
{
8+
public Task BeginTransactionAsync() => Task.CompletedTask;
9+
public Task CommitAsync() => Task.CompletedTask;
10+
public Task RollbackAsync() => Task.CompletedTask;
11+
public ValueTask DisposeAsync() => ValueTask.CompletedTask;
12+
}
13+
}
14+

ECommerce.BusinessEvents/Services/EventTrackingService.cs

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,16 @@
77
using ECommerce.Contracts.DTOs;
88
using ECommerce.Contracts.Interfaces;
99
using ECommerce.Common;
10+
using ECommerce.BusinessEvents.Infrastructure;
1011

1112
namespace ECommerce.BusinessEvents.Services
1213
{
1314
public class EventTrackingService(
1415
BusinessEventDbContext dbContext,
1516
SchemaRegistryService schemaRegistry,
1617
IJsonSchemaValidator schemaValidator,
17-
ILogger<EventTrackingService> logger) : IBusinessEventService, IEventRetrievalService
18+
ILogger<EventTrackingService> logger,
19+
ITransactionManager transactionManager) : IBusinessEventService, IEventRetrievalService
1820
{
1921
public async Task<Result<Unit, string>> TrackEventAsync(BusinessEventDto businessEventDto)
2022
{
@@ -41,9 +43,7 @@ public async Task<Result<Unit, string>> TrackEventAsync(BusinessEventDto busines
4143
return Result<Unit, string>.Failure(validationResult.Error!);
4244
}
4345

44-
// Use transaction to ensure both BusinessEvent and BusinessEventMetadata are saved together
45-
using var transaction = await dbContext.Database.BeginTransactionAsync();
46-
46+
await transactionManager.BeginTransactionAsync();
4747
try
4848
{
4949
var businessEvent = new BusinessEvent
@@ -75,20 +75,24 @@ public async Task<Result<Unit, string>> TrackEventAsync(BusinessEventDto busines
7575

7676
if (!metadataResult.IsSuccess)
7777
{
78-
await transaction.RollbackAsync();
78+
await transactionManager.RollbackAsync();
7979
return Result<Unit, string>.Failure($"Metadata save failed: {metadataResult.Error}");
8080
}
8181

82-
await transaction.CommitAsync();
82+
await transactionManager.CommitAsync();
8383
logger.LogInformation("Successfully tracked business event {EventId} with metadata", businessEvent.EventId);
8484

8585
return Result<Unit, string>.Success(new Unit());
8686
}
8787
catch (Exception ex)
8888
{
89-
await transaction.RollbackAsync();
90-
logger.LogError(ex, "Transaction failed while tracking business event for entity {EntityType}:{EntityId}", entityType, businessEventDto.EntityId);
91-
return Result<Unit, string>.Failure($"Transaction failed: {ex.Message}");
89+
logger.LogError(ex, "Failed to track business event for entity type {EntityType}", entityType);
90+
await transactionManager.RollbackAsync();
91+
return Result<Unit, string>.Failure($"Failed to track business event: {ex.Message}");
92+
}
93+
finally
94+
{
95+
await transactionManager.DisposeAsync();
9296
}
9397
}
9498

ECommerceApp.IntegrationTests/CustomWebApplicationFactory.cs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88
using Microsoft.Extensions.DependencyInjection;
99

1010
namespace ECommerceApp.IntegrationTests;
11-
1211
public class CustomWebApplicationFactory<TStartup> : WebApplicationFactory<TStartup>
1312
where TStartup : class
1413
{

0 commit comments

Comments
 (0)