Add tests
This commit is contained in:
1 parent
d5127c7405
commit
88aaaecb1a
15 files changed
+1755
-34
No files matched your search
@@ -0,0 +1,275 @@
|
||||
using BudgetApp.Data;
|
||||
using BudgetApp.Services;
|
||||
using BudgetApp.Tests.Helpers;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Xunit;
|
||||
|
||||
namespace BudgetApp.Tests.Services;
|
||||
|
||||
public class CategoryServiceTests
|
||||
{
|
||||
[Fact]
|
||||
public async Task GetCategoriesAsync_ReturnsOnlyUserCategories()
|
||||
{
|
||||
using var factory = new TestDbContextFactory();
|
||||
using (var ctx = factory.CreateContext())
|
||||
{
|
||||
ctx.Categories.AddRange(
|
||||
new Category { Name = "Mine", UserId = TestDbContextFactory.TestUserId },
|
||||
new Category { Name = "Theirs", UserId = TestDbContextFactory.OtherUserId });
|
||||
await ctx.SaveChangesAsync();
|
||||
}
|
||||
|
||||
using var context = factory.CreateContext();
|
||||
var service = new CategoryService(context);
|
||||
|
||||
var result = await service.GetCategoriesAsync(TestDbContextFactory.TestUserId);
|
||||
|
||||
Assert.Single(result);
|
||||
Assert.Equal("Mine", result[0].Name);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetCategoriesAsync_OrderedByName()
|
||||
{
|
||||
using var factory = new TestDbContextFactory();
|
||||
using (var ctx = factory.CreateContext())
|
||||
{
|
||||
ctx.Categories.AddRange(
|
||||
new Category { Name = "Zebra", UserId = TestDbContextFactory.TestUserId },
|
||||
new Category { Name = "Alpha", UserId = TestDbContextFactory.TestUserId });
|
||||
await ctx.SaveChangesAsync();
|
||||
}
|
||||
|
||||
using var context = factory.CreateContext();
|
||||
var service = new CategoryService(context);
|
||||
|
||||
var result = await service.GetCategoriesAsync(TestDbContextFactory.TestUserId);
|
||||
|
||||
Assert.Equal("Alpha", result[0].Name);
|
||||
Assert.Equal("Zebra", result[1].Name);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task EnsureDefaultCategoriesAsync_CreatesDefaults_WhenEmpty()
|
||||
{
|
||||
using var factory = new TestDbContextFactory();
|
||||
using var context = factory.CreateContext();
|
||||
var service = new CategoryService(context);
|
||||
|
||||
await service.EnsureDefaultCategoriesAsync(TestDbContextFactory.TestUserId);
|
||||
|
||||
using var verifyCtx = factory.CreateContext();
|
||||
var categories = await verifyCtx.Categories
|
||||
.Where(c => c.UserId == TestDbContextFactory.TestUserId)
|
||||
.ToListAsync();
|
||||
|
||||
Assert.Equal(15, categories.Count);
|
||||
Assert.Contains(categories, c => c.Name == "Groceries" && c.Icon == "🛒");
|
||||
Assert.Contains(categories, c => c.Name == "Transport" && c.Icon == "🚗");
|
||||
Assert.Contains(categories, c => c.Name == "Salary" && c.Icon == "💰");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task EnsureDefaultCategoriesAsync_DoesNotDuplicate_WhenCalledAgain()
|
||||
{
|
||||
using var factory = new TestDbContextFactory();
|
||||
|
||||
using (var ctx = factory.CreateContext())
|
||||
{
|
||||
var service = new CategoryService(ctx);
|
||||
await service.EnsureDefaultCategoriesAsync(TestDbContextFactory.TestUserId);
|
||||
}
|
||||
|
||||
using (var ctx = factory.CreateContext())
|
||||
{
|
||||
var service = new CategoryService(ctx);
|
||||
await service.EnsureDefaultCategoriesAsync(TestDbContextFactory.TestUserId);
|
||||
}
|
||||
|
||||
using var verifyCtx = factory.CreateContext();
|
||||
var count = await verifyCtx.Categories
|
||||
.Where(c => c.UserId == TestDbContextFactory.TestUserId)
|
||||
.CountAsync();
|
||||
|
||||
Assert.Equal(15, count);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task EnsureDefaultCategoriesAsync_BackfillsIcons_WhenMissing()
|
||||
{
|
||||
using var factory = new TestDbContextFactory();
|
||||
using (var ctx = factory.CreateContext())
|
||||
{
|
||||
ctx.Categories.Add(new Category
|
||||
{
|
||||
Name = "Groceries",
|
||||
Icon = "",
|
||||
UserId = TestDbContextFactory.TestUserId
|
||||
});
|
||||
await ctx.SaveChangesAsync();
|
||||
}
|
||||
|
||||
using var context = factory.CreateContext();
|
||||
var service = new CategoryService(context);
|
||||
await service.EnsureDefaultCategoriesAsync(TestDbContextFactory.TestUserId);
|
||||
|
||||
using var verifyCtx = factory.CreateContext();
|
||||
var category = await verifyCtx.Categories
|
||||
.SingleAsync(c => c.Name == "Groceries" && c.UserId == TestDbContextFactory.TestUserId);
|
||||
|
||||
Assert.Equal("🛒", category.Icon);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task EnsureDefaultCategoriesAsync_DoesNotOverwrite_ExistingIcons()
|
||||
{
|
||||
using var factory = new TestDbContextFactory();
|
||||
using (var ctx = factory.CreateContext())
|
||||
{
|
||||
ctx.Categories.Add(new Category
|
||||
{
|
||||
Name = "Groceries",
|
||||
Icon = "🥕",
|
||||
UserId = TestDbContextFactory.TestUserId
|
||||
});
|
||||
await ctx.SaveChangesAsync();
|
||||
}
|
||||
|
||||
using var context = factory.CreateContext();
|
||||
var service = new CategoryService(context);
|
||||
await service.EnsureDefaultCategoriesAsync(TestDbContextFactory.TestUserId);
|
||||
|
||||
using var verifyCtx = factory.CreateContext();
|
||||
var category = await verifyCtx.Categories
|
||||
.SingleAsync(c => c.Name == "Groceries" && c.UserId == TestDbContextFactory.TestUserId);
|
||||
|
||||
Assert.Equal("🥕", category.Icon);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task EnsureDefaultCategoriesAsync_IsolatedPerUser()
|
||||
{
|
||||
using var factory = new TestDbContextFactory();
|
||||
|
||||
using (var ctx = factory.CreateContext())
|
||||
{
|
||||
var service = new CategoryService(ctx);
|
||||
await service.EnsureDefaultCategoriesAsync(TestDbContextFactory.TestUserId);
|
||||
}
|
||||
|
||||
using (var ctx = factory.CreateContext())
|
||||
{
|
||||
var service = new CategoryService(ctx);
|
||||
await service.EnsureDefaultCategoriesAsync(TestDbContextFactory.OtherUserId);
|
||||
}
|
||||
|
||||
using var verifyCtx = factory.CreateContext();
|
||||
var totalCount = await verifyCtx.Categories.CountAsync();
|
||||
Assert.Equal(30, totalCount);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task CreateCategoryAsync_AddsToDatabase()
|
||||
{
|
||||
using var factory = new TestDbContextFactory();
|
||||
using var context = factory.CreateContext();
|
||||
var service = new CategoryService(context);
|
||||
|
||||
await service.CreateCategoryAsync(new Category
|
||||
{
|
||||
Name = "Custom",
|
||||
Icon = "🎯",
|
||||
UserId = TestDbContextFactory.TestUserId
|
||||
});
|
||||
|
||||
using var verifyCtx = factory.CreateContext();
|
||||
Assert.Single(verifyCtx.Categories);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task UpdateCategoryAsync_UpdatesNameAndIcon()
|
||||
{
|
||||
using var factory = new TestDbContextFactory();
|
||||
int categoryId;
|
||||
using (var ctx = factory.CreateContext())
|
||||
{
|
||||
var category = new Category { Name = "Old", Icon = "📁", UserId = TestDbContextFactory.TestUserId };
|
||||
ctx.Categories.Add(category);
|
||||
await ctx.SaveChangesAsync();
|
||||
categoryId = category.Id;
|
||||
}
|
||||
|
||||
using var context = factory.CreateContext();
|
||||
var service = new CategoryService(context);
|
||||
await service.UpdateCategoryAsync(categoryId, TestDbContextFactory.TestUserId, "New", "🎯");
|
||||
|
||||
using var verifyCtx = factory.CreateContext();
|
||||
var updated = verifyCtx.Categories.Single();
|
||||
Assert.Equal("New", updated.Name);
|
||||
Assert.Equal("🎯", updated.Icon);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task UpdateCategoryAsync_WrongUser_DoesNothing()
|
||||
{
|
||||
using var factory = new TestDbContextFactory();
|
||||
int categoryId;
|
||||
using (var ctx = factory.CreateContext())
|
||||
{
|
||||
var category = new Category { Name = "Original", Icon = "📁", UserId = TestDbContextFactory.TestUserId };
|
||||
ctx.Categories.Add(category);
|
||||
await ctx.SaveChangesAsync();
|
||||
categoryId = category.Id;
|
||||
}
|
||||
|
||||
using var context = factory.CreateContext();
|
||||
var service = new CategoryService(context);
|
||||
await service.UpdateCategoryAsync(categoryId, TestDbContextFactory.OtherUserId, "Hacked", "💀");
|
||||
|
||||
using var verifyCtx = factory.CreateContext();
|
||||
Assert.Equal("Original", verifyCtx.Categories.Single().Name);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task DeleteCategoryAsync_RemovesCategory()
|
||||
{
|
||||
using var factory = new TestDbContextFactory();
|
||||
int categoryId;
|
||||
using (var ctx = factory.CreateContext())
|
||||
{
|
||||
var category = new Category { Name = "ToDelete", UserId = TestDbContextFactory.TestUserId };
|
||||
ctx.Categories.Add(category);
|
||||
await ctx.SaveChangesAsync();
|
||||
categoryId = category.Id;
|
||||
}
|
||||
|
||||
using var context = factory.CreateContext();
|
||||
var service = new CategoryService(context);
|
||||
await service.DeleteCategoryAsync(categoryId, TestDbContextFactory.TestUserId);
|
||||
|
||||
using var verifyCtx = factory.CreateContext();
|
||||
Assert.Empty(verifyCtx.Categories);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task DeleteCategoryAsync_WrongUser_DoesNothing()
|
||||
{
|
||||
using var factory = new TestDbContextFactory();
|
||||
int categoryId;
|
||||
using (var ctx = factory.CreateContext())
|
||||
{
|
||||
var category = new Category { Name = "Protected", UserId = TestDbContextFactory.TestUserId };
|
||||
ctx.Categories.Add(category);
|
||||
await ctx.SaveChangesAsync();
|
||||
categoryId = category.Id;
|
||||
}
|
||||
|
||||
using var context = factory.CreateContext();
|
||||
var service = new CategoryService(context);
|
||||
await service.DeleteCategoryAsync(categoryId, TestDbContextFactory.OtherUserId);
|
||||
|
||||
using var verifyCtx = factory.CreateContext();
|
||||
Assert.Single(verifyCtx.Categories);
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user