Files
LehrerApp/LehrerApp.Tests/AttendanceBalanceServiceTests.cs
T
adminandClaude Sonnet 5 d987b93315 Schülerdokumentation: Einträge, Fehlzeitenbilanz, Datenschutz (Kapitel 5)
Dokumentationseinträge mit Typwahl (Gespräch, Vorkommnis, Förderplan,
Fehlzeit, Elternanruf, Elternbrief), vertrauliche Einträge nur nach
Bestätigung sichtbar, weiche Löschung mit Nachvollziehbarkeit. Fehlzeiten
als Auswertung des bestehenden Anwesenheits-Trackings statt zweiter
Erfassung, mit Schwellenwert-Warnung im Schülerdetail und Dashboard.
Förderplan-Wiedervorlage als Dashboard-Karte. Datenschutz: Löschfristen
mit manueller Bereinigung und DSGVO-Art.-15-Datenauskunft als Export.

Auf Nutzer-Feedback hin ergänzt: Elternanruf mit begleitendem
Gesprächsprotokoll-Dialog (Punkte abhaken, Eindrücke festhalten),
Elternbrief mit Versand-/Rückmeldungs-Tracking, Datei-Anhänge über
LiteDBs Dateispeicher, frei vergebbare Labels zur Nachverfolgung mit
Dringlichkeits-Farbcodierung, sowie eine sichtbare Farblegende für das
bestehende Notenentwicklungs-Diagramm. Dabei einen Absturz behoben:
leere Textfelder lieferten über das Binding null statt "", was beim
Speichern eine NullReferenceException auslöste.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-13 17:49:03 +02:00

89 lines
3.0 KiB
C#

using LehrerApp.Core.Models;
using LehrerApp.Core.Services;
using Xunit;
namespace LehrerApp.Tests;
public sealed class AttendanceBalanceServiceTests
{
private readonly AttendanceBalanceService _service = new();
private static readonly DateOnly From = new(2025, 8, 1);
private static readonly DateOnly To = new(2026, 7, 31);
[Fact]
public void Calculate_ZaehltJedenStatusKorrekt()
{
var entries = new List<(DateOnly, AttendanceStatus?)>
{
(new DateOnly(2025, 9, 1), AttendanceStatus.Present),
(new DateOnly(2025, 9, 2), AttendanceStatus.Present),
(new DateOnly(2025, 9, 3), AttendanceStatus.Excused),
(new DateOnly(2025, 9, 4), AttendanceStatus.Unexcused),
(new DateOnly(2025, 9, 5), AttendanceStatus.Truant),
(new DateOnly(2025, 9, 6), AttendanceStatus.OtherSchoolEvent),
(new DateOnly(2025, 9, 7), AttendanceStatus.ExcusePending),
};
var balance = _service.Calculate(entries, From, To);
Assert.Equal(7, balance.TotalChecked);
Assert.Equal(2, balance.Present);
Assert.Equal(1, balance.Excused);
Assert.Equal(2, balance.Unexcused); // Unexcused + Truant
Assert.Equal(1, balance.SchoolEvent);
Assert.Equal(1, balance.ExcusePending);
}
[Fact]
public void Calculate_IgnoriertEintraegeOhneStatusUndAusserhalbDesZeitraums()
{
var entries = new List<(DateOnly, AttendanceStatus?)>
{
(new DateOnly(2025, 9, 1), null),
(new DateOnly(2024, 9, 1), AttendanceStatus.Unexcused), // vor dem Zeitraum
(new DateOnly(2025, 9, 1), AttendanceStatus.Present),
};
var balance = _service.Calculate(entries, From, To);
Assert.Equal(1, balance.TotalChecked);
Assert.Equal(1, balance.Present);
}
[Fact]
public void Calculate_SchulischVeranlassteAbwesenheitZaehltNichtAlsFehlzeit()
{
var entries = new List<(DateOnly, AttendanceStatus?)>
{
(new DateOnly(2025, 9, 1), AttendanceStatus.OtherSchoolEvent),
(new DateOnly(2025, 9, 2), AttendanceStatus.Present),
};
var balance = _service.Calculate(entries, From, To);
Assert.Equal(0.0, balance.AbsenceRatePercent);
}
[Fact]
public void ExceedsThreshold_UeberZwanzigProzentFehlquote_IstTrue()
{
var entries = Enumerable.Range(0, 10)
.Select(i => (From.AddDays(i), (AttendanceStatus?)(i < 3 ? AttendanceStatus.Unexcused : AttendanceStatus.Present)))
.ToList();
var balance = _service.Calculate(entries, From, To);
Assert.Equal(30.0, balance.AbsenceRatePercent);
Assert.True(balance.ExceedsThreshold);
}
[Fact]
public void ExceedsThreshold_KeineKontrolliertenStunden_IstFalseUndRateIstNull()
{
var balance = _service.Calculate([], From, To);
Assert.Equal(0.0, balance.AbsenceRatePercent);
Assert.False(balance.ExceedsThreshold);
}
}