Arbeitszeit: wiederkehrende Aufgaben + Auto-Aufgabe bei Klausurkorrektur (6.1.4/6.1.5)
Damit ist Kapitel 6 (Arbeitszeit & Aufgaben) vollständig abgeschlossen (bis auf den Export der Auswertung, der an das noch fehlende Kapitel 11 hängt). - WorkTask.Recurrence (None/Weekly/Monthly): beim Abschließen einer wiederkehrenden Aufgabe wird automatisch die nächste Instanz mit verschobenem Fälligkeitsdatum erzeugt. - GroupDetailViewModel.SetExamStatus legt beim ersten Wechsel einer Klausur von "Geplant" auf "Durchgeführt" automatisch eine Korrektur-Aufgabe an.
This commit is contained in:
@@ -0,0 +1,72 @@
|
||||
using LehrerApp.Core.Models;
|
||||
using LehrerApp.Core.Services;
|
||||
using LehrerApp.Desktop.ViewModels.Groups;
|
||||
using Xunit;
|
||||
|
||||
namespace LehrerApp.Desktop.Tests;
|
||||
|
||||
public sealed class GroupDetailViewModelTests
|
||||
{
|
||||
private static (GroupDetailViewModel Vm, FakeExams Exams, FakeWorkTasks Tasks) Build(LearningGroup group, Exam exam)
|
||||
{
|
||||
var exams = new FakeExams([exam]);
|
||||
var tasks = new FakeWorkTasks();
|
||||
var groups = new FakeGroups([group]);
|
||||
var students = new FakeStudents([]);
|
||||
var memberships = new FakeMemberships([]);
|
||||
var subjects = new FakeSubjects([]);
|
||||
var grades = new FakeGrades();
|
||||
|
||||
var vm = new GroupDetailViewModel(groups, students, memberships, subjects, exams, grades, tasks,
|
||||
new ParticipationTabViewModel(new FakeSessions([]), new FakeEntries(), new FakeAspects(),
|
||||
students, memberships, groups, new FakeCompetencyDomains()),
|
||||
new GradeOverviewTabViewModel(grades, exams, new FakeResults(), students, memberships, new GradingService()),
|
||||
new PlanningTabViewModel(new FakeUnits(), new FakeLessons(), groups, subjects, new FakeCompetencyDomains()));
|
||||
|
||||
vm.LoadGroup(group.Id);
|
||||
vm.SelectedExam = vm.Exams.First(e => e.Id == exam.Id);
|
||||
return (vm, exams, tasks);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SetExamStatus_PlannedZuConducted_ErstelltKorrekturAufgabe()
|
||||
{
|
||||
var group = new LearningGroup { Name = "8a", SchoolYear = "2025/26" };
|
||||
var exam = new Exam { GroupId = group.Id, Title = "Klausur 1", Date = new DateOnly(2026, 3, 10) };
|
||||
var (vm, _, tasks) = Build(group, exam);
|
||||
|
||||
vm.SetExamStatusCommand.Execute(ExamStatus.Conducted);
|
||||
|
||||
var task = Assert.Single(tasks.GetAll());
|
||||
Assert.Equal("Klausur korrigieren: Klausur 1", task.Title);
|
||||
Assert.Equal(TaskCategory.Correction, task.Category);
|
||||
Assert.Equal(group.Id, task.GroupId);
|
||||
Assert.Equal(new DateOnly(2026, 3, 24), task.DueDate);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SetExamStatus_ConductedErneutGesetzt_ErstelltKeineZweiteAufgabe()
|
||||
{
|
||||
var group = new LearningGroup { Name = "8a", SchoolYear = "2025/26" };
|
||||
var exam = new Exam { GroupId = group.Id, Title = "Klausur 1", Date = new DateOnly(2026, 3, 10) };
|
||||
var (vm, _, tasks) = Build(group, exam);
|
||||
|
||||
vm.SetExamStatusCommand.Execute(ExamStatus.Conducted);
|
||||
vm.SelectedExam = vm.Exams.First(e => e.Id == exam.Id);
|
||||
vm.SetExamStatusCommand.Execute(ExamStatus.Conducted);
|
||||
|
||||
Assert.Single(tasks.GetAll());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SetExamStatus_DirektAufGraded_ErstelltKeineAufgabe()
|
||||
{
|
||||
var group = new LearningGroup { Name = "8a", SchoolYear = "2025/26" };
|
||||
var exam = new Exam { GroupId = group.Id, Title = "Klausur 1", Date = new DateOnly(2026, 3, 10) };
|
||||
var (vm, _, tasks) = Build(group, exam);
|
||||
|
||||
vm.SetExamStatusCommand.Execute(ExamStatus.Graded);
|
||||
|
||||
Assert.Empty(tasks.GetAll());
|
||||
}
|
||||
}
|
||||
@@ -93,6 +93,66 @@ public sealed class WorkTaskListViewModelTests
|
||||
Assert.Equal(WorkTaskStatus.Open, vm.Tasks[0].Model.Status);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CycleStatus_WoechentlicheWiederholungAufErledigt_ErzeugtNaechsteInstanz()
|
||||
{
|
||||
var tasks = new FakeWorkTasks();
|
||||
tasks.Add(new WorkTask
|
||||
{
|
||||
Title = "Wochenbericht", Status = WorkTaskStatus.InProgress,
|
||||
Recurrence = TaskRecurrence.Weekly, DueDate = new DateOnly(2026, 3, 10),
|
||||
Category = TaskCategory.Admin,
|
||||
});
|
||||
var vm = new WorkTaskListViewModel(tasks, new FakeGroups([]), new FakeTimeEntries())
|
||||
{
|
||||
StatusFilter = WorkTaskListViewModel.AllFilter,
|
||||
};
|
||||
|
||||
vm.CycleStatusCommand.Execute(vm.Tasks[0]); // -> Done
|
||||
|
||||
var all = tasks.GetAll();
|
||||
Assert.Equal(2, all.Count);
|
||||
var next = all.Single(t => t.Status == WorkTaskStatus.Open);
|
||||
Assert.Equal("Wochenbericht", next.Title);
|
||||
Assert.Equal(new DateOnly(2026, 3, 17), next.DueDate);
|
||||
Assert.Equal(TaskRecurrence.Weekly, next.Recurrence);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CycleStatus_MonatlicheWiederholung_AddiertEinenMonat()
|
||||
{
|
||||
var tasks = new FakeWorkTasks();
|
||||
tasks.Add(new WorkTask
|
||||
{
|
||||
Title = "Bericht", Status = WorkTaskStatus.InProgress,
|
||||
Recurrence = TaskRecurrence.Monthly, DueDate = new DateOnly(2026, 3, 10),
|
||||
});
|
||||
var vm = new WorkTaskListViewModel(tasks, new FakeGroups([]), new FakeTimeEntries())
|
||||
{
|
||||
StatusFilter = WorkTaskListViewModel.AllFilter,
|
||||
};
|
||||
|
||||
vm.CycleStatusCommand.Execute(vm.Tasks[0]); // -> Done
|
||||
|
||||
var next = tasks.GetAll().Single(t => t.Status == WorkTaskStatus.Open);
|
||||
Assert.Equal(new DateOnly(2026, 4, 10), next.DueDate);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CycleStatus_OhneWiederholung_ErzeugtKeineNeueAufgabe()
|
||||
{
|
||||
var tasks = new FakeWorkTasks();
|
||||
tasks.Add(new WorkTask { Title = "T", Status = WorkTaskStatus.InProgress });
|
||||
var vm = new WorkTaskListViewModel(tasks, new FakeGroups([]), new FakeTimeEntries())
|
||||
{
|
||||
StatusFilter = WorkTaskListViewModel.AllFilter,
|
||||
};
|
||||
|
||||
vm.CycleStatusCommand.Execute(vm.Tasks[0]); // -> Done
|
||||
|
||||
Assert.Single(tasks.GetAll());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void DeleteTask_EntferntAufgabeAusDerListe()
|
||||
{
|
||||
@@ -193,6 +253,37 @@ public sealed class AddEditWorkTaskDialogViewModelTests
|
||||
Assert.Equal(source.Id, vm.Result!.Id);
|
||||
Assert.Equal(WorkTaskStatus.InProgress, vm.Result.Status);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Save_WiederholungOhneFaelligkeitsdatum_SetztFehler()
|
||||
{
|
||||
var vm = new AddEditWorkTaskDialogViewModel(null, [])
|
||||
{
|
||||
Title = "T",
|
||||
SelectedRecurrence = TaskRecurrenceDisplay.Label(TaskRecurrence.Weekly),
|
||||
};
|
||||
|
||||
vm.SaveCommand.Execute(null);
|
||||
|
||||
Assert.Null(vm.Result);
|
||||
Assert.NotEmpty(vm.DueDateError);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Save_WiederholungMitFaelligkeitsdatum_UebernimmtRecurrence()
|
||||
{
|
||||
var vm = new AddEditWorkTaskDialogViewModel(null, [])
|
||||
{
|
||||
Title = "T",
|
||||
DueDateText = "10.03.2026",
|
||||
SelectedRecurrence = TaskRecurrenceDisplay.Label(TaskRecurrence.Monthly),
|
||||
};
|
||||
|
||||
vm.SaveCommand.Execute(null);
|
||||
|
||||
Assert.NotNull(vm.Result);
|
||||
Assert.Equal(TaskRecurrence.Monthly, vm.Result!.Recurrence);
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class TimeTrackingViewModelTests
|
||||
|
||||
Reference in New Issue
Block a user