234 lines
6.9 KiB
C#
234 lines
6.9 KiB
C#
// EN: Unit tests for Wallet aggregate with multi-currency support
|
|
// VI: Unit tests cho Wallet aggregate với hỗ trợ đa tiền tệ
|
|
using WalletService.Domain.AggregatesModel.WalletAggregate;
|
|
using WalletService.Domain.Exceptions;
|
|
using Xunit;
|
|
|
|
namespace WalletService.UnitTests.Domain;
|
|
|
|
public class WalletTests
|
|
{
|
|
private static readonly Guid TestUserId = Guid.NewGuid();
|
|
|
|
[Fact]
|
|
public void Constructor_ShouldCreateWallet_WithZeroBalance()
|
|
{
|
|
// Arrange & Act
|
|
var wallet = new Wallet(TestUserId, CurrencyType.VND);
|
|
|
|
// Assert
|
|
Assert.NotNull(wallet);
|
|
Assert.Equal(TestUserId, wallet.UserId);
|
|
Assert.Equal(CurrencyType.VND.Id, wallet.DefaultCurrencyTypeId);
|
|
Assert.Equal(0, wallet.GetBalance(CurrencyType.VND));
|
|
Assert.Equal(WalletStatus.Active, wallet.Status);
|
|
}
|
|
|
|
[Fact]
|
|
public void Constructor_ShouldDefaultToVND_WhenNoCurrencyProvided()
|
|
{
|
|
// Arrange & Act
|
|
var wallet = new Wallet(TestUserId);
|
|
|
|
// Assert
|
|
Assert.Equal(CurrencyType.VND.Id, wallet.DefaultCurrencyTypeId);
|
|
}
|
|
|
|
[Fact]
|
|
public void Deposit_ShouldIncreaseBalance()
|
|
{
|
|
// Arrange
|
|
var wallet = new Wallet(TestUserId, CurrencyType.VND);
|
|
|
|
// Act
|
|
wallet.Deposit(100000m, CurrencyType.VND, "Test deposit", "REF001");
|
|
|
|
// Assert
|
|
Assert.Equal(100000m, wallet.GetBalance(CurrencyType.VND));
|
|
Assert.Single(wallet.Transactions);
|
|
Assert.Equal(TransactionType.Credit, wallet.Transactions.First().Type);
|
|
}
|
|
|
|
[Fact]
|
|
public void CreateMoney_ShouldThrow_WhenAmountIsNegative()
|
|
{
|
|
// Arrange & Act & Assert
|
|
// EN: Money constructor throws ArgumentException for negative amounts
|
|
// VI: Money constructor ném ArgumentException cho số tiền âm
|
|
Assert.Throws<ArgumentException>(() =>
|
|
new Money(-100, "VND"));
|
|
}
|
|
|
|
[Fact]
|
|
public void Withdraw_ShouldDecreaseBalance()
|
|
{
|
|
// Arrange
|
|
var wallet = new Wallet(TestUserId, CurrencyType.VND);
|
|
wallet.Deposit(100000m, CurrencyType.VND, "Initial deposit", "REF001");
|
|
|
|
// Act
|
|
wallet.Withdraw(50000m, CurrencyType.VND, "Test withdrawal", "REF002");
|
|
|
|
// Assert
|
|
Assert.Equal(50000m, wallet.GetBalance(CurrencyType.VND));
|
|
Assert.Equal(2, wallet.Transactions.Count);
|
|
}
|
|
|
|
[Fact]
|
|
public void Withdraw_ShouldThrow_WhenInsufficientBalance()
|
|
{
|
|
// Arrange
|
|
var wallet = new Wallet(TestUserId, CurrencyType.VND);
|
|
wallet.Deposit(50000m, CurrencyType.VND, "Initial deposit", "REF001");
|
|
|
|
// Act & Assert
|
|
Assert.Throws<InsufficientBalanceException>(() =>
|
|
wallet.Withdraw(100000m, CurrencyType.VND, "Invalid withdrawal"));
|
|
}
|
|
|
|
[Fact]
|
|
public void Freeze_ShouldSetStatusToFrozen()
|
|
{
|
|
// Arrange
|
|
var wallet = new Wallet(TestUserId, CurrencyType.VND);
|
|
|
|
// Act
|
|
wallet.Freeze();
|
|
|
|
// Assert
|
|
Assert.Equal(WalletStatus.Frozen, wallet.Status);
|
|
}
|
|
|
|
[Fact]
|
|
public void Unfreeze_ShouldSetStatusToActive()
|
|
{
|
|
// Arrange
|
|
var wallet = new Wallet(TestUserId, CurrencyType.VND);
|
|
wallet.Freeze();
|
|
|
|
// Act
|
|
wallet.Unfreeze();
|
|
|
|
// Assert
|
|
Assert.Equal(WalletStatus.Active, wallet.Status);
|
|
}
|
|
|
|
[Fact]
|
|
public void Close_ShouldSetStatusToClosed()
|
|
{
|
|
// Arrange
|
|
var wallet = new Wallet(TestUserId, CurrencyType.VND);
|
|
|
|
// Act
|
|
wallet.Close();
|
|
|
|
// Assert
|
|
Assert.Equal(WalletStatus.Closed, wallet.Status);
|
|
}
|
|
|
|
[Fact]
|
|
public void Close_ShouldThrow_WhenBalanceIsPositive()
|
|
{
|
|
// Arrange
|
|
var wallet = new Wallet(TestUserId, CurrencyType.VND);
|
|
wallet.Deposit(100000m, CurrencyType.VND, "Deposit", "REF001");
|
|
|
|
// Act & Assert
|
|
Assert.Throws<WalletDomainException>(() => wallet.Close());
|
|
}
|
|
|
|
#region Multi-Currency Tests / Tests đa tiền tệ
|
|
|
|
[Fact]
|
|
public void Deposit_ShouldSupportMultipleCurrencies()
|
|
{
|
|
// Arrange
|
|
var wallet = new Wallet(TestUserId, CurrencyType.VND);
|
|
|
|
// Act
|
|
wallet.Deposit(100000m, CurrencyType.VND, "VND deposit");
|
|
wallet.Deposit(100m, CurrencyType.USD, "USD deposit");
|
|
wallet.Deposit(1000, CurrencyType.PPoint, "PPoint deposit");
|
|
|
|
// Assert
|
|
Assert.Equal(100000m, wallet.GetBalance(CurrencyType.VND));
|
|
Assert.Equal(100m, wallet.GetBalance(CurrencyType.USD));
|
|
Assert.Equal(1000, wallet.GetBalance(CurrencyType.PPoint));
|
|
Assert.Equal(3, wallet.Balances.Count);
|
|
}
|
|
|
|
[Fact]
|
|
public void Exchange_ShouldConvertBetweenCurrencies()
|
|
{
|
|
// Arrange
|
|
var wallet = new Wallet(TestUserId, CurrencyType.VND);
|
|
wallet.Deposit(100000m, CurrencyType.VND, "Initial VND deposit");
|
|
|
|
// Act - Exchange 100000 VND to PPoint (rate: 1 VND = 0.001 PPoint)
|
|
var receivedPoints = wallet.Exchange(100000m, CurrencyType.VND, CurrencyType.PPoint);
|
|
|
|
// Assert
|
|
Assert.Equal(0, wallet.GetBalance(CurrencyType.VND));
|
|
Assert.Equal(100, wallet.GetBalance(CurrencyType.PPoint)); // 100000 / 1000 = 100
|
|
}
|
|
|
|
[Fact]
|
|
public void Exchange_ShouldThrow_WhenSameCurrency()
|
|
{
|
|
// Arrange
|
|
var wallet = new Wallet(TestUserId, CurrencyType.VND);
|
|
wallet.Deposit(100000m, CurrencyType.VND, "Deposit");
|
|
|
|
// Act & Assert
|
|
Assert.Throws<WalletDomainException>(() =>
|
|
wallet.Exchange(50000m, CurrencyType.VND, CurrencyType.VND));
|
|
}
|
|
|
|
[Fact]
|
|
public void Exchange_ShouldThrow_WhenInsufficientBalance()
|
|
{
|
|
// Arrange
|
|
var wallet = new Wallet(TestUserId, CurrencyType.VND);
|
|
wallet.Deposit(50000m, CurrencyType.VND, "Deposit");
|
|
|
|
// Act & Assert
|
|
Assert.Throws<InsufficientBalanceException>(() =>
|
|
wallet.Exchange(100000m, CurrencyType.VND, CurrencyType.PPoint));
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Escrow Tests / Tests Ký Quỹ
|
|
|
|
[Fact]
|
|
public void Hold_ShouldReduceAvailableBalanceAndCreateHoldItem()
|
|
{
|
|
// Arrange
|
|
var wallet = new Wallet(TestUserId, CurrencyType.VND);
|
|
wallet.Deposit(1000m, CurrencyType.VND, "Init", "REF001");
|
|
|
|
// Act
|
|
var hold = wallet.Hold(100m, CurrencyType.VND, "REF", Guid.NewGuid(), "Desc");
|
|
|
|
// Assert
|
|
Assert.Equal(900m, wallet.GetBalance(CurrencyType.VND));
|
|
Assert.Single(wallet.Holds);
|
|
Assert.Equal(100m, wallet.GetTotalHeldAmount(CurrencyType.VND));
|
|
Assert.Equal(HoldStatus.Active, hold.Status);
|
|
}
|
|
|
|
[Fact]
|
|
public void Hold_ShouldThrow_WhenInsufficientBalance()
|
|
{
|
|
// Arrange
|
|
var wallet = new Wallet(TestUserId, CurrencyType.VND);
|
|
wallet.Deposit(50m, CurrencyType.VND, "Init", "REF001");
|
|
|
|
// Act & Assert
|
|
Assert.Throws<InsufficientBalanceException>(() =>
|
|
wallet.Hold(100m, CurrencyType.VND, "REF", Guid.NewGuid(), "Desc"));
|
|
}
|
|
|
|
#endregion
|
|
}
|