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:
AJ
2025-10-26 00:01:28 -04:00
parent f8bb5d5a82
commit af4a638b81
10 changed files with 1679 additions and 0 deletions

View File

@@ -0,0 +1,221 @@
using MoneyMap.Models;
using MoneyMap.Services;
using MoneyMap.Tests.TestHelpers;
using Xunit;
namespace MoneyMap.Tests.Services;
public class ReferenceDataServiceTests
{
[Fact]
public async Task GetAvailableCategoriesAsync_ReturnsDistinctSortedCategories()
{
// Arrange
using var context = DbContextHelper.CreateInMemoryContext();
var service = new ReferenceDataService(context);
var account = new Account
{
Id = 1,
Institution = "Test Bank",
AccountType = AccountType.Checking,
Last4 = "1234",
Owner = "Test Owner"
};
context.Accounts.Add(account);
var transaction1 = new Transaction
{
Date = DateTime.Now,
Amount = -50.00m,
Name = "Test",
Memo = "Test",
AccountId = 1,
Category = "Groceries"
};
var transaction2 = new Transaction
{
Date = DateTime.Now,
Amount = -30.00m,
Name = "Test",
Memo = "Test",
AccountId = 1,
Category = "Gas"
};
var transaction3 = new Transaction
{
Date = DateTime.Now,
Amount = -20.00m,
Name = "Test",
Memo = "Test",
AccountId = 1,
Category = "Groceries" // Duplicate
};
context.Transactions.AddRange(transaction1, transaction2, transaction3);
await context.SaveChangesAsync();
// Act
var result = await service.GetAvailableCategoriesAsync();
// Assert
Assert.Equal(2, result.Count);
Assert.Contains("Groceries", result);
Assert.Contains("Gas", result);
Assert.Equal("Gas", result[0]); // Alphabetically sorted
Assert.Equal("Groceries", result[1]);
}
[Fact]
public async Task GetAvailableCategoriesAsync_ExcludesEmptyCategories()
{
// Arrange
using var context = DbContextHelper.CreateInMemoryContext();
var service = new ReferenceDataService(context);
var account = new Account
{
Id = 1,
Institution = "Test Bank",
AccountType = AccountType.Checking,
Last4 = "1234",
Owner = "Test Owner"
};
context.Accounts.Add(account);
var transaction1 = new Transaction
{
Date = DateTime.Now,
Amount = -50.00m,
Name = "Test",
Memo = "Test",
AccountId = 1,
Category = "Groceries"
};
var transaction2 = new Transaction
{
Date = DateTime.Now,
Amount = -30.00m,
Name = "Test",
Memo = "Test",
AccountId = 1,
Category = "" // Empty
};
var transaction3 = new Transaction
{
Date = DateTime.Now,
Amount = -20.00m,
Name = "Test",
Memo = "Test",
AccountId = 1,
Category = " " // Whitespace
};
context.Transactions.AddRange(transaction1, transaction2, transaction3);
await context.SaveChangesAsync();
// Act
var result = await service.GetAvailableCategoriesAsync();
// Assert
Assert.Single(result);
Assert.Equal("Groceries", result[0]);
}
[Fact]
public async Task GetAvailableMerchantsAsync_ReturnsSortedMerchants()
{
// Arrange
using var context = DbContextHelper.CreateInMemoryContext();
var service = new ReferenceDataService(context);
var merchant1 = new Merchant { Name = "Walmart" };
var merchant2 = new Merchant { Name = "Amazon" };
var merchant3 = new Merchant { Name = "Target" };
context.Merchants.AddRange(merchant1, merchant2, merchant3);
await context.SaveChangesAsync();
// Act
var result = await service.GetAvailableMerchantsAsync();
// Assert
Assert.Equal(3, result.Count);
Assert.Equal("Amazon", result[0].Name); // Alphabetically sorted
Assert.Equal("Target", result[1].Name);
Assert.Equal("Walmart", result[2].Name);
}
[Fact]
public async Task GetAvailableCardsAsync_ReturnsSortedCards()
{
// Arrange
using var context = DbContextHelper.CreateInMemoryContext();
var service = new ReferenceDataService(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
{
AccountId = 1,
Issuer = "VISA",
Last4 = "3333",
Owner = "Bob"
};
var card2 = new Card
{
AccountId = 1,
Issuer = "Mastercard",
Last4 = "1111",
Owner = "Alice"
};
context.Cards.AddRange(card1, card2);
await context.SaveChangesAsync();
// Act
var result = await service.GetAvailableCardsAsync();
// Assert
Assert.Equal(2, result.Count);
Assert.Equal("Alice", result[0].Owner); // Sorted by owner
Assert.Equal("Bob", result[1].Owner);
}
[Fact]
public async Task GetAvailableAccountsAsync_ReturnsSortedAccounts()
{
// Arrange
using var context = DbContextHelper.CreateInMemoryContext();
var service = new ReferenceDataService(context);
var account1 = new Account
{
Institution = "Wells Fargo",
AccountType = AccountType.Checking,
Last4 = "5678",
Owner = "Test"
};
var account2 = new Account
{
Institution = "Bank of America",
AccountType = AccountType.Savings,
Last4 = "1234",
Owner = "Test"
};
context.Accounts.AddRange(account1, account2);
await context.SaveChangesAsync();
// Act
var result = await service.GetAvailableAccountsAsync();
// Assert
Assert.Equal(2, result.Count);
Assert.Equal("Bank of America", result[0].Institution); // Sorted by institution
Assert.Equal("Wells Fargo", result[1].Institution);
}
}