Files
LehrerApp/LehrerApp.Tests/ReportGradeTargetCalculatorTests.cs
T
adminandClaude Sonnet 5 1215d4ac22
CI / build-and-test (push) Canceled after 0s
Tagesflagge im Sitzplan, Leistungsüberblick mit Zielnoten-Rechner
- Mitarbeit: Tagesflagge (👑 Spitzentag / 😴 Schlaftag /  Schlechter Tag)
  je Schüler und Sitzung. Primär im Sitzplatz-Dialog (⇧1/2/3, ⇧X) mit
  Badge auf der Sitzplatz-Kachel; Fallback in der Schnelleingabe für
  Lerngruppen ohne Sitzplan.
- Noten: neuer Dialog "Überblick" in der Notenübersicht zeigt Klausuren,
  Mitarbeit- und sonstige Noten eines Schülers samt berechneter
  Zeugnisnote. Zielnoten-Rechner (ReportGradeTargetCalculator) beantwortet
  "was brauche ich noch für Note X", ein Was-wäre-wenn-Rechner simuliert
  eine zusätzliche Klausurnote. Bewerter-/Schülermodus per Umschalter im
  selben Fenster — Bewertermodus zeigt zusätzlich Kursdurchschnitt je
  Klausur und erlaubt das Bearbeiten von Mitarbeit-/Sonstige-Noten.
  Klausurverlauf als Balken-Sparkline wie die bestehende Notenentwicklung.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-30 11:43:47 +02:00

82 lines
3.4 KiB
C#

using LehrerApp.Core.Models;
using LehrerApp.Core.Services;
using Xunit;
namespace LehrerApp.Tests;
/// Tests für die Zielnoten-Frage (Nutzer-Feedback): "Was brauche ich noch, um Note X zu
/// erreichen?" — Umkehrung von GradingService.CalculateReportGrade.
public sealed class ReportGradeTargetCalculatorTests
{
private static readonly GradingScheme Scheme = new()
{
ExamsPercent = 50, ParticipationPercent = 30, OtherPercent = 20,
};
[Fact]
public void SolveRequiredAverage_LoestNachDemGesuchtenBereichAuf()
{
// Ziel 2,0; Mitarbeit 3,0 (30%), Sonstige 2,0 (20%) bekannt -> Klausuren (50%) gesucht.
// 2,0 * 100 = x*50 + 3,0*30 + 2,0*20 => 200 = 50x + 90 + 40 => x = 1,4
var result = ReportGradeTargetCalculator.SolveRequiredAverage(
2.0, GradeBucketKind.Exams, examsAverage: null, participationAverage: 3.0, otherAverage: 2.0,
Scheme, GradingSystem.Grades1To6);
Assert.NotNull(result);
Assert.Equal(1.4, result!.Value.RequiredAverage, precision: 4);
Assert.True(result.Value.IsAchievable);
}
[Fact]
public void SolveRequiredAverage_IgnoriertBereicheOhneBekanntenDurchschnitt()
{
// Nur Klausuren (50%) bekannt, Mitarbeit gesucht (30%), Sonstige ohne Daten (fällt raus).
// Ziel 2,0 nur aus Klausuren(50%, Ø 2,0) + Mitarbeit(30%, gesucht) => Gesamtprozent 80.
// 2,0*80 = 2,0*50 + x*30 => 160 = 100 + 30x => x = 2,0
var result = ReportGradeTargetCalculator.SolveRequiredAverage(
2.0, GradeBucketKind.Participation, examsAverage: 2.0, participationAverage: null, otherAverage: null,
Scheme, GradingSystem.Grades1To6);
Assert.NotNull(result);
Assert.Equal(2.0, result!.Value.RequiredAverage, precision: 4);
}
[Fact]
public void SolveRequiredAverage_AusserhalbDesGueltigenBereichs_IstNichtErreichbar()
{
// Mitarbeit bereits sehr schlecht (5,5) -> selbst eine Traumnote in Klausuren reicht nicht für 1,5.
var result = ReportGradeTargetCalculator.SolveRequiredAverage(
1.5, GradeBucketKind.Exams, examsAverage: null, participationAverage: 5.5, otherAverage: null,
Scheme, GradingSystem.Grades1To6);
Assert.NotNull(result);
Assert.False(result!.Value.IsAchievable);
}
[Fact]
public void SolveRequiredAverage_BereichOhneGewichtungsanteil_GibtNullZurueck()
{
var scheme = new GradingScheme { ExamsPercent = 100, ParticipationPercent = 0, OtherPercent = 0 };
var result = ReportGradeTargetCalculator.SolveRequiredAverage(
2.0, GradeBucketKind.Participation, examsAverage: 2.0, participationAverage: null, otherAverage: null,
scheme, GradingSystem.Grades1To6);
Assert.Null(result);
}
[Fact]
public void SolveRequiredAverage_FunktioniertAufDerPunkteskala()
{
// Punktesystem: höher ist besser. Ziel 12 Punkte, Mitarbeit 10 (30%), Sonstige 8 (20%)
// bekannt -> Klausuren (50%) gesucht. 12*100 = x*50+10*30+8*20 => 1200=50x+300+160 => x=14,8
var result = ReportGradeTargetCalculator.SolveRequiredAverage(
12.0, GradeBucketKind.Exams, examsAverage: null, participationAverage: 10.0, otherAverage: 8.0,
Scheme, GradingSystem.Points0To15);
Assert.NotNull(result);
Assert.Equal(14.8, result!.Value.RequiredAverage, precision: 4);
Assert.True(result.Value.IsAchievable);
}
}