Test: add comprehensive unit test project for services
Add MoneyMap.Tests project with xUnit tests for all new services: - AccountServiceTests: Account retrieval, stats, validation, deletion - CardServiceTests: Card retrieval, stats, validation, deletion - MerchantServiceTests: Merchant CRUD operations - ReferenceDataServiceTests: Reference data retrieval - TransactionServiceTests: Duplicate detection, retrieval, deletion - TransactionStatisticsServiceTests: Statistics calculations - ReceiptMatchingServiceTests: Receipt-to-transaction matching logic - DbContextHelper: In-memory database context factory for test isolation Uses xUnit, Moq, and EF Core InMemory database. Solution file updated to include test project. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
188
MoneyMap.Tests/Services/TransactionStatisticsServiceTests.cs
Normal file
188
MoneyMap.Tests/Services/TransactionStatisticsServiceTests.cs
Normal file
@@ -0,0 +1,188 @@
|
||||
using MoneyMap.Models;
|
||||
using MoneyMap.Services;
|
||||
using MoneyMap.Tests.TestHelpers;
|
||||
using Xunit;
|
||||
|
||||
namespace MoneyMap.Tests.Services;
|
||||
|
||||
public class TransactionStatisticsServiceTests
|
||||
{
|
||||
[Fact]
|
||||
public async Task CalculateStatsAsync_ReturnsCorrectStatistics()
|
||||
{
|
||||
// Arrange
|
||||
using var context = DbContextHelper.CreateInMemoryContext();
|
||||
var service = new TransactionStatisticsService(context);
|
||||
|
||||
var account = new Account
|
||||
{
|
||||
Id = 1,
|
||||
Institution = "Test Bank",
|
||||
AccountType = AccountType.Checking,
|
||||
Last4 = "1234",
|
||||
Owner = "Test Owner"
|
||||
};
|
||||
context.Accounts.Add(account);
|
||||
|
||||
var debit1 = new Transaction
|
||||
{
|
||||
Date = DateTime.Now,
|
||||
Amount = -50.00m,
|
||||
Name = "Store A",
|
||||
Memo = "Purchase",
|
||||
AccountId = 1
|
||||
};
|
||||
var debit2 = new Transaction
|
||||
{
|
||||
Date = DateTime.Now,
|
||||
Amount = -30.00m,
|
||||
Name = "Store B",
|
||||
Memo = "Purchase",
|
||||
AccountId = 1
|
||||
};
|
||||
var credit = new Transaction
|
||||
{
|
||||
Date = DateTime.Now,
|
||||
Amount = 100.00m,
|
||||
Name = "Deposit",
|
||||
Memo = "Paycheck",
|
||||
AccountId = 1
|
||||
};
|
||||
context.Transactions.AddRange(debit1, debit2, credit);
|
||||
await context.SaveChangesAsync();
|
||||
|
||||
var query = context.Transactions.AsQueryable();
|
||||
|
||||
// Act
|
||||
var result = await service.CalculateStatsAsync(query);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(3, result.Count);
|
||||
Assert.Equal(-80.00m, result.TotalDebits);
|
||||
Assert.Equal(100.00m, result.TotalCredits);
|
||||
Assert.Equal(20.00m, result.NetAmount);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetCategorizationStatsAsync_ReturnsCorrectCounts()
|
||||
{
|
||||
// Arrange
|
||||
using var context = DbContextHelper.CreateInMemoryContext();
|
||||
var service = new TransactionStatisticsService(context);
|
||||
|
||||
var account = new Account
|
||||
{
|
||||
Id = 1,
|
||||
Institution = "Test Bank",
|
||||
AccountType = AccountType.Checking,
|
||||
Last4 = "1234",
|
||||
Owner = "Test Owner"
|
||||
};
|
||||
context.Accounts.Add(account);
|
||||
|
||||
var categorized1 = new Transaction
|
||||
{
|
||||
Date = DateTime.Now,
|
||||
Amount = -50.00m,
|
||||
Name = "Test",
|
||||
Memo = "Test",
|
||||
AccountId = 1,
|
||||
Category = "Groceries"
|
||||
};
|
||||
var categorized2 = new Transaction
|
||||
{
|
||||
Date = DateTime.Now,
|
||||
Amount = -30.00m,
|
||||
Name = "Test",
|
||||
Memo = "Test",
|
||||
AccountId = 1,
|
||||
Category = "Gas"
|
||||
};
|
||||
var uncategorized = new Transaction
|
||||
{
|
||||
Date = DateTime.Now,
|
||||
Amount = -20.00m,
|
||||
Name = "Test",
|
||||
Memo = "Test",
|
||||
AccountId = 1,
|
||||
Category = ""
|
||||
};
|
||||
context.Transactions.AddRange(categorized1, categorized2, uncategorized);
|
||||
await context.SaveChangesAsync();
|
||||
|
||||
// Act
|
||||
var result = await service.GetCategorizationStatsAsync();
|
||||
|
||||
// Assert
|
||||
Assert.Equal(3, result.TotalTransactions);
|
||||
Assert.Equal(2, result.Categorized);
|
||||
Assert.Equal(1, result.Uncategorized);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetCardStatsForAccountAsync_ReturnsStatsForLinkedCards()
|
||||
{
|
||||
// Arrange
|
||||
using var context = DbContextHelper.CreateInMemoryContext();
|
||||
var service = new TransactionStatisticsService(context);
|
||||
|
||||
var account = new Account
|
||||
{
|
||||
Id = 1,
|
||||
Institution = "Test Bank",
|
||||
AccountType = AccountType.Checking,
|
||||
Last4 = "1234",
|
||||
Owner = "Test Owner"
|
||||
};
|
||||
context.Accounts.Add(account);
|
||||
|
||||
var card1 = new Card
|
||||
{
|
||||
Id = 1,
|
||||
AccountId = 1,
|
||||
Issuer = "VISA",
|
||||
Last4 = "1111",
|
||||
Owner = "Test"
|
||||
};
|
||||
var card2 = new Card
|
||||
{
|
||||
Id = 2,
|
||||
AccountId = 1,
|
||||
Issuer = "Mastercard",
|
||||
Last4 = "2222",
|
||||
Owner = "Test"
|
||||
};
|
||||
context.Cards.AddRange(card1, card2);
|
||||
|
||||
var transaction1 = new Transaction
|
||||
{
|
||||
Date = DateTime.Now,
|
||||
Amount = -50.00m,
|
||||
Name = "Test",
|
||||
Memo = "Test",
|
||||
AccountId = 1,
|
||||
CardId = 1
|
||||
};
|
||||
var transaction2 = new Transaction
|
||||
{
|
||||
Date = DateTime.Now,
|
||||
Amount = -30.00m,
|
||||
Name = "Test",
|
||||
Memo = "Test",
|
||||
AccountId = 1,
|
||||
CardId = 1
|
||||
};
|
||||
context.Transactions.AddRange(transaction1, transaction2);
|
||||
await context.SaveChangesAsync();
|
||||
|
||||
// Act
|
||||
var result = await service.GetCardStatsForAccountAsync(1);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(2, result.Count);
|
||||
var card1Stats = result.First(c => c.Card.Id == 1);
|
||||
Assert.Equal(2, card1Stats.TransactionCount);
|
||||
var card2Stats = result.First(c => c.Card.Id == 2);
|
||||
Assert.Equal(0, card2Stats.TransactionCount);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user