using Domain.Entities.Members; using Domain.Entities.Payments; using Domain.Entities.Payments.ValueObject; using Infrastructure.Persistence; using Microsoft.EntityFrameworkCore; // 공유 LocalDB(antooza_test) 기반 통합 테스트 — 병렬 실행 시 싱글턴 Config(최신 row) 를 // 여러 테스트가 동시 seed/read 하여 교차오염된다. 직렬화로 프로덕션의 단일 Config 가정을 보장. [assembly: Microsoft.VisualStudio.TestTools.UnitTesting.DoNotParallelize] namespace Application.Tests; /// /// LocalDB 기반 테스트 DB. 운영과 동일한 SQL Server 프로바이더를 사용해 /// rowversion 동시성·유니크 인덱스 등 관계형 동작을 그대로 검증한다. /// [TestClass] public sealed class TestDb { // ANTOOZA_TEST_DB 환경변수로 연결 문자열 재정의 가능 — LocalDB API(인스턴스 디스커버리)가 세션 컨텍스트 문제로 실패할 때 // 직접 파이프(np:\\.\pipe\LOCALDB#...\tsql\query) 등으로 우회 실행하기 위함. 미설정 시 기존 LocalDB 기본값. private static readonly string ConnectionString = Environment.GetEnvironmentVariable("ANTOOZA_TEST_DB") ?? @"Server=(localdb)\MSSQLLocalDB;Database=antooza_test;Integrated Security=True;TrustServerCertificate=True;"; public static DbContextOptions Options { get; } = new DbContextOptionsBuilder().UseSqlServer(ConnectionString).Options; public static AppDbContext Create() => new(Options); [AssemblyInitialize] public static void AssemblyInit(TestContext _) { using var db = Create(); db.Database.EnsureDeleted(); db.Database.EnsureCreated(); } public static async Task CreateMemberAsync(AppDbContext db) { var member = Member.Create($"test-{Guid.NewGuid():N}@antooza.test"); await db.Member.AddAsync(member); await db.SaveChangesAsync(default); return member.ID; } public static async Task CreateOrderAsync(AppDbContext db, int memberID, int pointAmount = 10000, bool paid = false) { var order = PaymentOrder.Create(memberID, $"ORD-{Guid.NewGuid():N}", "TOSS", pointAmount, PaymentMethod.Integrated); if (paid) { // TossConfirm.PaymentKey 에 unique 인덱스가 있고 테스트 DB 는 어셈블리 단위로 공유되므로 // 주문별 고유 paymentKey(TransactionID)를 부여해 테스트 간 시드 충돌을 방지한다. order.MarkPaid($"TX-{Guid.NewGuid():N}"); } await db.PaymentOrder.AddAsync(order); await db.SaveChangesAsync(default); return order; } }