Testabdeckung Kapitel 13.1 (Tests, Fehlerbehandlung)

Vier neue xUnit-Testprojekte (LehrerApp.Tests, .Data.Tests, .Desktop.Tests,
.Sync.Tests) mit zusammen 104 Tests: GradingService, SchoolYearService,
Repositories gegen In-Memory-LiteDB, Mitarbeits-Aggregation (3.2),
Zeugnisnotenberechnung (2.4) und ConflictResolver.

Dabei zwei echte Fehler in der Sync-Schicht gefunden und behoben:
- SyncEvent.EventId fehlte [BsonId], wodurch EventQueue.Acknowledge()
  nie etwas aus der Queue löschte.
- ConflictResolver verglich Zeitstempel unterschiedlicher DateTimeKind
  direkt (LiteDB liefert Local statt Utc zurück), was die Gleichstand-
  Regel außerhalb von UTC+0 verfälschte.

SchoolYearService.CurrentSchoolYear()/RecentSchoolYears() um ein optionales
today-Argument erweitert, um den Schuljahreswechsel deterministisch zu
testen; LiteDbContext um einen Stream-Konstruktor für In-Memory-Tests.
This commit is contained in:
2026-08-13 11:05:06 +02:00
parent a8b8a40b52
commit 273f459119
15 changed files with 1558 additions and 14 deletions
+110
View File
@@ -0,0 +1,110 @@
using LehrerApp.Core.Services;
using Xunit;
namespace LehrerApp.Tests;
public class SchoolYearServiceTests
{
private readonly SchoolYearService _sut = new();
// ── FormatSchoolYear ──────────────────────────────────────────────────────
[Fact]
public void FormatSchoolYear_NormalerJahrgang()
{
Assert.Equal("2025/26", _sut.FormatSchoolYear(2025));
}
[Fact]
public void FormatSchoolYear_JahrhundertwechselWirdZweistelligDargestellt()
{
// 1999 -> 2000, aber zweistellig als "00", nicht "100" oder leer.
Assert.Equal("1999/00", _sut.FormatSchoolYear(1999));
}
// ── CurrentSchoolYear: Jahreswechsel am 1. August ────────────────────────
[Fact]
public void CurrentSchoolYear_AmSchuljahreswechsel_ZaehltBereitsDasNeueJahr()
{
// 1. August ist der erste Tag des neuen Schuljahres.
var result = _sut.CurrentSchoolYear(new DateOnly(2025, 8, 1));
Assert.Equal("2025/26", result);
}
[Fact]
public void CurrentSchoolYear_TagVorDemWechsel_GehoertNochZumAltenSchuljahr()
{
// 31. Juli ist der letzte Tag des alten Schuljahres.
var result = _sut.CurrentSchoolYear(new DateOnly(2025, 7, 31));
Assert.Equal("2024/25", result);
}
[Fact]
public void CurrentSchoolYear_MittenImHerbst_GehoertZumLaufendenSchuljahr()
{
var result = _sut.CurrentSchoolYear(new DateOnly(2025, 11, 15));
Assert.Equal("2025/26", result);
}
[Fact]
public void CurrentSchoolYear_ImJanuar_GehoertNochZumImVorjahrBegonnenenSchuljahr()
{
// Der Kalenderjahreswechsel (1. Januar) ist NICHT der Schuljahreswechsel.
var result = _sut.CurrentSchoolYear(new DateOnly(2026, 1, 15));
Assert.Equal("2025/26", result);
}
[Fact]
public void CurrentSchoolYear_OhneParameter_VerwendetHeutigesDatum()
{
var expectedStartYear = DateTime.Today.Month >= 8 ? DateTime.Today.Year : DateTime.Today.Year - 1;
Assert.Equal(_sut.FormatSchoolYear(expectedStartYear), _sut.CurrentSchoolYear());
}
// ── SchoolYearStart / SchoolYearEnd ──────────────────────────────────────
[Fact]
public void SchoolYearStart_ErsterAugust()
{
Assert.Equal(new DateOnly(2025, 8, 1), _sut.SchoolYearStart("2025/26"));
}
[Fact]
public void SchoolYearEnd_EinunddreissigsterJuliDesFolgejahres()
{
Assert.Equal(new DateOnly(2026, 7, 31), _sut.SchoolYearEnd("2025/26"));
}
[Fact]
public void SchoolYearStartUndEnd_SchliessenLueckenlosAneinanderAn()
{
// Kein Tag darf zwischen zwei aufeinanderfolgenden Schuljahren fehlen oder sich überlappen.
var endeAlt = _sut.SchoolYearEnd("2025/26");
var startNeu = _sut.SchoolYearStart("2026/27");
Assert.Equal(startNeu, endeAlt.AddDays(1));
}
// ── RecentSchoolYears ─────────────────────────────────────────────────────
[Fact]
public void RecentSchoolYears_GibtAnzahlWieAngefordertZurueck()
{
var result = _sut.RecentSchoolYears(3, new DateOnly(2025, 9, 1));
Assert.Equal(["2025/26", "2024/25", "2023/24"], result);
}
[Fact]
public void RecentSchoolYears_StandardanzahlIstFuenf()
{
var result = _sut.RecentSchoolYears(today: new DateOnly(2025, 9, 1));
Assert.Equal(5, result.Count);
}
[Fact]
public void RecentSchoolYears_ErsterEintragIstDasAktuelleSchuljahr()
{
var today = new DateOnly(2025, 3, 1); // Januar-Fall: gehört noch zu 2024/25
Assert.Equal(_sut.CurrentSchoolYear(today), _sut.RecentSchoolYears(today: today)[0]);
}
}