From 1396d85a0fca2057fd21afa4f584467ae408ea29 Mon Sep 17 00:00:00 2001 From: Stefan Koelle Date: Sun, 9 Aug 2026 16:21:25 +0200 Subject: [PATCH] dotnet xUnit Tests --- AGENTS.md | 5 + Directory.Build.props | 2 +- FocusApp.Tests/FocusApp.Tests.csproj | 28 ++++ FocusApp.Tests/FocusTasksControllerTests.cs | 158 ++++++++++++++++++++ 4 files changed, 192 insertions(+), 1 deletion(-) create mode 100644 FocusApp.Tests/FocusApp.Tests.csproj create mode 100644 FocusApp.Tests/FocusTasksControllerTests.cs diff --git a/AGENTS.md b/AGENTS.md index 5e1c207..d10fcbc 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -5,6 +5,11 @@ - Nach jeder CSS-Anpassung (`*.css` Dateien) immer `cd client && npm run build` ausfuehren um zu pruefen ob der Build fehlerfrei durchlaeuft - Nach Aenderungen an Komponenten-Dateien (`*.tsx`) ebenfalls `npm run build` ausfuehren +## .NET / Backend + +- Nach Aenderungen an `.cs` Dateien immer `dotnet build` ausfuehren +- Anschliessend `dotnet test` im `FocusApp.Tests` Verzeichnis ausfuehren + ## Docker - Nach Aenderungen am `Dockerfile` oder `docker-compose.yml` immer `docker build .` ausfuehren diff --git a/Directory.Build.props b/Directory.Build.props index 4c6ac8c..e0e4e39 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -1,7 +1,7 @@ - $(DefaultItemExcludes);client\node_modules\** + $(DefaultItemExcludes);client\node_modules\**;FocusApp.Tests\** true diff --git a/FocusApp.Tests/FocusApp.Tests.csproj b/FocusApp.Tests/FocusApp.Tests.csproj new file mode 100644 index 0000000..d1a573f --- /dev/null +++ b/FocusApp.Tests/FocusApp.Tests.csproj @@ -0,0 +1,28 @@ + + + + net10.0 + enable + enable + false + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/FocusApp.Tests/FocusTasksControllerTests.cs b/FocusApp.Tests/FocusTasksControllerTests.cs new file mode 100644 index 0000000..b5eeaaf --- /dev/null +++ b/FocusApp.Tests/FocusTasksControllerTests.cs @@ -0,0 +1,158 @@ +// Copyright (c) 2026 Stefan Koelle (https://stefankoelle.de) +// Licensed under the MIT License. See LICENSE file in project root for details. +using FocusApp.Controllers; +using FocusApp.Data; +using FocusApp.Models; +using Microsoft.AspNetCore.Mvc; +using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.Logging; +using Xunit; + +namespace FocusApp.Tests; + +public class FocusTasksControllerTests : IDisposable +{ + private readonly FocusContext _context; + private readonly FocusTasksController _controller; + private readonly ILogger _logger; + + public FocusTasksControllerTests() + { + var options = new DbContextOptionsBuilder() + .UseInMemoryDatabase(databaseName: Guid.NewGuid().ToString()) + .Options; + + _context = new FocusContext(options); + _logger = new LoggerFactory().CreateLogger(); + _controller = new FocusTasksController(_context, _logger); + } + + public void Dispose() + { + _context.Database.EnsureDeleted(); + _context.Dispose(); + } + + [Fact] + public async Task GetTasks_ReturnsEmptyList_WhenNoTasks() + { + var result = await _controller.GetTasks(); + + var okResult = Assert.IsType(result.Result); + var tasks = Assert.IsAssignableFrom>(okResult.Value); + Assert.Empty(tasks); + } + + [Fact] + public async Task CreateTask_ReturnsCreatedAtAction_WithValidData() + { + var dto = new CreateTaskDto { Title = "Test Task", Description = "Test Description" }; + + var result = await _controller.CreateTask(dto); + + var createdResult = Assert.IsType(result.Result); + var task = Assert.IsType(createdResult.Value); + Assert.Equal("Test Task", task.Title); + Assert.Equal("Test Description", task.Description); + Assert.Equal(1, task.Order); + } + + [Fact] + public async Task CreateTask_ReturnsBadRequest_WhenTitleIsEmpty() + { + var dto = new CreateTaskDto { Title = "" }; + + var result = await _controller.CreateTask(dto); + + Assert.IsType(result.Result); + } + + [Fact] + public async Task CreateTask_ReturnsBadRequest_WhenTitleExceedsMaxLength() + { + var dto = new CreateTaskDto { Title = new string('A', 256) }; + + var result = await _controller.CreateTask(dto); + + Assert.IsType(result.Result); + } + + [Fact] + public async Task UpdateTask_ReturnsOk_WithValidData() + { + var createDto = new CreateTaskDto { Title = "Original" }; + var created = await _controller.CreateTask(createDto); + var createdTask = (created.Result as CreatedAtActionResult)!.Value as FocusTask; + + var updateDto = new UpdateTaskDto { Title = "Updated" }; + var result = await _controller.UpdateTask(createdTask!.Id, updateDto); + + var okResult = Assert.IsType(result); + var task = Assert.IsType(okResult.Value); + Assert.Equal("Updated", task.Title); + } + + [Fact] + public async Task UpdateTask_ReturnsNotFound_WhenTaskDoesNotExist() + { + var dto = new UpdateTaskDto { Title = "Updated" }; + + var result = await _controller.UpdateTask(999, dto); + + Assert.IsType(result); + } + + [Fact] + public async Task DeleteTask_ReturnsNoContent_WhenTaskExists() + { + var createDto = new CreateTaskDto { Title = "To Delete" }; + var created = await _controller.CreateTask(createDto); + var createdTask = (created.Result as CreatedAtActionResult)!.Value as FocusTask; + + var result = await _controller.DeleteTask(createdTask!.Id); + + Assert.IsType(result); + } + + [Fact] + public async Task DeleteTask_ReturnsNotFound_WhenTaskDoesNotExist() + { + var result = await _controller.DeleteTask(999); + + Assert.IsType(result); + } + + [Fact] + public async Task ReorderTasks_ReturnsOk_WithValidOrders() + { + var task1 = await _controller.CreateTask(new CreateTaskDto { Title = "Task 1" }); + var task2 = await _controller.CreateTask(new CreateTaskDto { Title = "Task 2" }); + var t1 = (task1.Result as CreatedAtActionResult)!.Value as FocusTask; + var t2 = (task2.Result as CreatedAtActionResult)!.Value as FocusTask; + + var reorderDto = new ReorderDto + { + Orders = new List + { + new OrderItem { Id = t1!.Id, Order = 2 }, + new OrderItem { Id = t2!.Id, Order = 1 } + } + }; + + var result = await _controller.ReorderTasks(reorderDto); + + var okResult = Assert.IsType(result); + var tasks = Assert.IsAssignableFrom>(okResult.Value); + Assert.Equal(2, tasks.Count()); + } + + [Fact] + public async Task ReorderTasks_ReturnsBadRequest_WhenNoOrders() + { + var reorderDto = new ReorderDto { Orders = new List() }; + + var result = await _controller.ReorderTasks(reorderDto); + + Assert.IsType(result); + } +}