CI / build-and-test (push) Canceled after 0s
Das Verlassen eines unveränderten Punktefelds löste Autosave aus; leere Zellen wurden als 0 gespeichert und ergaben Note 6. Zellen melden nur noch echte Änderungen, Zeilen ohne Werte werden nicht angelegt und haben keine Note. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
229 lines
8.6 KiB
C#
229 lines
8.6 KiB
C#
using LehrerApp.Core.Interfaces;
|
|
using LehrerApp.Core.Models;
|
|
using LehrerApp.Core.Services;
|
|
using LehrerApp.Desktop.ViewModels.Groups;
|
|
using Xunit;
|
|
|
|
namespace LehrerApp.Desktop.Tests;
|
|
|
|
/// Deckt 1.6.3 (Bulk-Aktion "Rest als abwesend markieren") ab — löst das Nutzer-Feedback, dass
|
|
/// Schüler, die nie nachschreiben, sonst dauerhaft eine leere, unberührte Zeile hinterlassen.
|
|
public sealed class ExamGradingDialogViewModelTests
|
|
{
|
|
[Fact]
|
|
public void MarkRemainingAbsent_MarktNurUnberührteZeilenAbwesend()
|
|
{
|
|
var group = new LearningGroup { Name = "Q1 Chemie" };
|
|
var studentWithPoints = new Student { FirstName = "Anna", LastName = "Bauer" };
|
|
var untouchedStudent1 = new Student { FirstName = "Ben", LastName = "Cordes" };
|
|
var untouchedStudent2 = new Student { FirstName = "Cara", LastName = "Diehl" };
|
|
var students = new FakeStudents([studentWithPoints, untouchedStudent1, untouchedStudent2]);
|
|
var memberships = new FakeMemberships(
|
|
[
|
|
new GroupMembership { GroupId = group.Id, StudentId = studentWithPoints.Id },
|
|
new GroupMembership { GroupId = group.Id, StudentId = untouchedStudent1.Id },
|
|
new GroupMembership { GroupId = group.Id, StudentId = untouchedStudent2.Id },
|
|
]);
|
|
var exam = new Exam
|
|
{
|
|
GroupId = group.Id,
|
|
Title = "Klausur 1",
|
|
Tasks = [new ExamTask { Nr = 1, MaxPoints = 10 }],
|
|
GradingKey = GradingService.DefaultKey1To6(),
|
|
};
|
|
var results = new FakeResults();
|
|
|
|
var vm = new ExamGradingDialogViewModel(results, students, memberships,
|
|
new GradingService(), exam, group.Id);
|
|
|
|
var rowWithPoints = vm.Rows.Single(r => r.StudentId == studentWithPoints.Id);
|
|
rowWithPoints.Cells[0].TrySetValue(7);
|
|
|
|
vm.MarkRemainingAbsentCommand.Execute(null);
|
|
|
|
Assert.False(rowWithPoints.Absent);
|
|
Assert.True(vm.Rows.Single(r => r.StudentId == untouchedStudent1.Id).Absent);
|
|
Assert.True(vm.Rows.Single(r => r.StudentId == untouchedStudent2.Id).Absent);
|
|
}
|
|
|
|
[Fact]
|
|
public void MarkRemainingAbsent_LässtBereitsAbwesendMarkierteUnverändert()
|
|
{
|
|
var group = new LearningGroup { Name = "Q1 Chemie" };
|
|
var student = new Student { FirstName = "Ben", LastName = "Cordes" };
|
|
var students = new FakeStudents([student]);
|
|
var memberships = new FakeMemberships(
|
|
[new GroupMembership { GroupId = group.Id, StudentId = student.Id }]);
|
|
var exam = new Exam { GroupId = group.Id, Title = "Klausur 1", Tasks = [new ExamTask { Nr = 1, MaxPoints = 10 }], GradingKey = GradingService.DefaultKey1To6() };
|
|
var vm = new ExamGradingDialogViewModel(new FakeResults(), students, memberships,
|
|
new GradingService(), exam, group.Id);
|
|
|
|
vm.Rows[0].Absent = true;
|
|
vm.MarkRemainingAbsentCommand.Execute(null);
|
|
|
|
Assert.True(vm.Rows[0].Absent);
|
|
}
|
|
|
|
private static ExamGradingDialogViewModel CreateGrid(int studentCount, params ExamTask[] tasks)
|
|
{
|
|
var group = new LearningGroup { Name = "Q1 Chemie" };
|
|
var students = Enumerable.Range(0, studentCount)
|
|
.Select(i => new Student { FirstName = "S", LastName = $"N{i}" }).ToList();
|
|
var memberships = new FakeMemberships(
|
|
students.Select(s => new GroupMembership { GroupId = group.Id, StudentId = s.Id }).ToList());
|
|
var exam = new Exam
|
|
{
|
|
GroupId = group.Id, Title = "Klausur 1", Tasks = [.. tasks],
|
|
GradingKey = GradingService.DefaultKey1To6(),
|
|
};
|
|
return new ExamGradingDialogViewModel(new FakeResults(), new FakeStudents(students), memberships,
|
|
new GradingService(), exam, group.Id);
|
|
}
|
|
|
|
private static ExamTask[] ThreeTasks() =>
|
|
[
|
|
new() { Nr = 1, MaxPoints = 5 },
|
|
new() { Nr = 2, MaxPoints = 5 },
|
|
new() { Nr = 3, MaxPoints = 5 },
|
|
];
|
|
|
|
[Fact]
|
|
public void Enter_SchülerFürSchüler_LäuftDieZeileEntlangUndDannInDieNächste()
|
|
{
|
|
var vm = CreateGrid(2, ThreeTasks());
|
|
|
|
Assert.Equal((0, 1), vm.NextCell(0, 0, GradingMove.Next));
|
|
Assert.Equal((1, 0), vm.NextCell(0, 2, GradingMove.Next));
|
|
Assert.Null(vm.NextCell(1, 2, GradingMove.Next));
|
|
Assert.Equal((0, 2), vm.NextCell(1, 0, GradingMove.Previous));
|
|
}
|
|
|
|
[Fact]
|
|
public void Enter_AufgabeFürAufgabe_LäuftDieSpalteHinunterUndDannZurNächstenAufgabe()
|
|
{
|
|
var vm = CreateGrid(2, ThreeTasks());
|
|
vm.EntryOrderName = vm.EntryOrderOptions[1];
|
|
|
|
Assert.Equal((1, 0), vm.NextCell(0, 0, GradingMove.Next));
|
|
Assert.Equal((0, 1), vm.NextCell(1, 0, GradingMove.Next));
|
|
Assert.Equal((1, 0), vm.NextCell(0, 1, GradingMove.Previous));
|
|
}
|
|
|
|
[Fact]
|
|
public void Navigation_ÜberspringtAbwesendeUndAndereFassung()
|
|
{
|
|
var vm = CreateGrid(3,
|
|
new ExamTask { Nr = 1, MaxPoints = 5 },
|
|
new ExamTask { Nr = 2, MaxPoints = 5, Variant = ExamVariant.B },
|
|
new ExamTask { Nr = 3, MaxPoints = 5 });
|
|
vm.Rows[1].Absent = true;
|
|
|
|
Assert.Equal((0, 2), vm.NextCell(0, 0, GradingMove.Next));
|
|
Assert.Equal((0, 2), vm.NextCell(0, 0, GradingMove.Right));
|
|
Assert.Equal((2, 0), vm.NextCell(0, 0, GradingMove.Down));
|
|
Assert.Null(vm.NextCell(0, 0, GradingMove.Up));
|
|
}
|
|
|
|
[Fact]
|
|
public void Spaltenüberschriften_ZählenBonusaufgabenNichtMit()
|
|
{
|
|
var vm = CreateGrid(1,
|
|
new ExamTask { Nr = 1, MaxPoints = 5 },
|
|
new ExamTask { Nr = 2, MaxPoints = 2, IsBonus = true },
|
|
new ExamTask { Nr = 3, MaxPoints = 5, Title = "Redox" });
|
|
|
|
Assert.Equal(["Aufgabe 1", "★ Bonus", "2. Redox"], vm.TaskHeaders);
|
|
}
|
|
|
|
private sealed class RecordingResults : FakeResults, IExamResultRepository
|
|
{
|
|
public List<ExamResult> Saved { get; } = [];
|
|
public new void Save(ExamResult result) => Saved.Add(result);
|
|
}
|
|
|
|
private static (ExamGradingDialogViewModel Vm, RecordingResults Results) CreateRecordingGrid(
|
|
ExamResult? existing = null)
|
|
{
|
|
var group = new LearningGroup { Name = "Q1 Chemie" };
|
|
var student = new Student { FirstName = "Ben", LastName = "Cordes" };
|
|
var exam = new Exam
|
|
{
|
|
GroupId = group.Id, Title = "Klausur 1", Tasks = [.. ThreeTasks()],
|
|
GradingKey = GradingService.DefaultKey1To6(),
|
|
};
|
|
var results = new RecordingResults();
|
|
if (existing is not null)
|
|
{
|
|
existing.ExamId = exam.Id; existing.StudentId = student.Id;
|
|
results.Add(existing);
|
|
}
|
|
var vm = new ExamGradingDialogViewModel(results, new FakeStudents([student]),
|
|
new FakeMemberships([new GroupMembership { GroupId = group.Id, StudentId = student.Id }]),
|
|
new GradingService(), exam, group.Id);
|
|
return (vm, results);
|
|
}
|
|
|
|
[Fact]
|
|
public void NurAngefahreneZelle_LegtKeinErgebnisMitNullPunktenAn()
|
|
{
|
|
var (vm, results) = CreateRecordingGrid();
|
|
|
|
// Fokus in die Zelle und wieder heraus ohne Eingabe: die View meldet das als TrySetValue(null).
|
|
vm.Rows[0].Cells[0].TrySetValue(null);
|
|
vm.Rows[0].Cells[1].TrySetValue(null);
|
|
|
|
Assert.Empty(results.Saved);
|
|
Assert.Equal("", vm.Rows[0].GradeDisplay);
|
|
}
|
|
|
|
[Fact]
|
|
public void ErsterEingetragenerWert_LegtDasErgebnisAn()
|
|
{
|
|
var (vm, results) = CreateRecordingGrid();
|
|
|
|
vm.Rows[0].Cells[0].TrySetValue(4);
|
|
|
|
var saved = Assert.Single(results.Saved);
|
|
Assert.Equal([4, 0, 0], saved.Points);
|
|
Assert.Equal(4, saved.TotalPoints);
|
|
}
|
|
|
|
[Fact]
|
|
public void UnveraenderterWert_SpeichertNichtErneut()
|
|
{
|
|
var (vm, results) = CreateRecordingGrid();
|
|
vm.Rows[0].Cells[0].TrySetValue(4);
|
|
|
|
vm.Rows[0].Cells[0].TrySetValue(4);
|
|
|
|
Assert.Single(results.Saved);
|
|
}
|
|
|
|
[Fact]
|
|
public void LeereZeileMitBestehendemErgebnis_WirdAlsUnkorrigiertGespeichertNichtAlsNull()
|
|
{
|
|
var (vm, results) = CreateRecordingGrid(
|
|
new ExamResult { Points = [4], TotalPoints = 4, Grade = "4" });
|
|
|
|
vm.Rows[0].Cells[0].TrySetValue(null);
|
|
|
|
var saved = Assert.Single(results.Saved);
|
|
Assert.Empty(saved.Points);
|
|
Assert.Null(saved.Grade);
|
|
Assert.False(ExamCoverSheetService.IsCorrected(saved));
|
|
}
|
|
|
|
[Fact]
|
|
public void AbwesendheitOhnePunkte_WirdOhnePunkteUndNoteGespeichert()
|
|
{
|
|
var (vm, results) = CreateRecordingGrid();
|
|
|
|
vm.Rows[0].Absent = true;
|
|
|
|
var saved = Assert.Single(results.Saved);
|
|
Assert.True(saved.Absent);
|
|
Assert.Empty(saved.Points);
|
|
Assert.Null(saved.Grade);
|
|
}
|
|
}
|