using Application.Abstractions.Payment; namespace Application.Tests; /// /// ITossPaymentService 수제 fake — PG 호출 횟수를 기록하고 설정된 결과/예외를 반환한다. /// internal sealed class FakeTossPaymentService : ITossPaymentService { public TossPaymentResult ConfirmResult { get; set; } = Done(); public Exception? ConfirmException { get; set; } public TossPaymentResult CancelResult { get; set; } = Cancelled(); public Exception? CancelException { get; set; } public TossPaymentResult GetPaymentResult { get; set; } = Done(); public Exception? GetPaymentException { get; set; } public int ConfirmCallCount { get; private set; } public int CancelCallCount { get; private set; } public int GetPaymentCallCount { get; private set; } public Task GetClientConfigAsync(CancellationToken ct) => Task.FromResult(new TossClientConfig("test_ck_fake")); public Task ConfirmAsync(string paymentKey, string orderID, int amount, CancellationToken ct) { ConfirmCallCount++; if (ConfirmException is not null) { throw ConfirmException; } return Task.FromResult(ConfirmResult); } public Task CancelAsync(string paymentKey, string cancelReason, int? cancelAmount, CancellationToken ct) { CancelCallCount++; if (CancelException is not null) { throw CancelException; } return Task.FromResult(CancelResult); } public Task GetPaymentAsync(string paymentKey, CancellationToken ct) { GetPaymentCallCount++; if (GetPaymentException is not null) { throw GetPaymentException; } return Task.FromResult(GetPaymentResult); } /// 승인/조회 성공 (status=DONE) public static TossPaymentResult Done(string? paymentKey = null, string? orderID = null, int? totalAmount = null) => new( Success: true, Code: null, Message: null, PaymentKey: paymentKey, OrderID: orderID, Status: "DONE", TotalAmount: totalAmount, Method: "카드", ApprovedAt: DateTime.UtcNow, ReceiptUrl: "https://receipt.antooza.test", VirtualAccountNumber: null, VirtualAccountBankCode: null, VirtualAccountHolder: null, VirtualAccountDueDate: null, Cancels: [], RawJson: "{}"); /// 토스의 명시적 거절 {code, message} public static TossPaymentResult Fail(string code = "REJECT_CARD_COMPANY", string message = "승인 거절") => Done() with { Success = false, Code = code, Message = message, Status = null }; /// 가상계좌 발급 (status=WAITING_FOR_DEPOSIT) public static TossPaymentResult WaitingDeposit() => Done() with { Status = "WAITING_FOR_DEPOSIT", VirtualAccountNumber = "9-4444-0000-1234", VirtualAccountBankCode = "20", VirtualAccountHolder = "개미투자", VirtualAccountDueDate = DateTime.UtcNow.AddDays(7) }; /// 취소 성공 (status=CANCELED, cancels[] 1건) public static TossPaymentResult Cancelled(int cancelAmount = 0) => Done() with { Status = "CANCELED", Cancels = new List { new("CANCEL-TX", cancelAmount, "취소", DateTime.UtcNow) } }; }