CI / build-and-test (push) Canceled after 0s
LearningGroup.PreviousGroupId wird von GroupRolloverService jetzt automatisch gesetzt; neue Karte "Vorjahresvergleich" im Kurs-Tab Übersicht zeigt den gepoolten Klausurdurchschnitt neben dem der Vorgängergruppe, sobald dort Ergebnisse vorliegen. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
113 lines
5.3 KiB
C#
113 lines
5.3 KiB
C#
using LehrerApp.Core.Interfaces;
|
|
using LehrerApp.Core.Models;
|
|
using LehrerApp.Core.Services;
|
|
using Xunit;
|
|
|
|
namespace LehrerApp.Tests;
|
|
|
|
public sealed class GroupRolloverServiceTests
|
|
{
|
|
[Fact]
|
|
public void RollOver_KopiertStammdatenUndErzeugtNeueGanzjaehrigeMitgliedschaften()
|
|
{
|
|
var source = new LearningGroup
|
|
{
|
|
Name = "8a", SchoolYear = "2025/26", GradeLevel = 8,
|
|
Type = GroupType.Class, SubjectId = Guid.NewGuid(), GradingSystem = GradingSystem.Grades1To6,
|
|
HoursPerWeek = 4, IsOwnClass = true, IsDifferentiated = true, WebUntisLessonId = 38262,
|
|
};
|
|
var oldMembership = new GroupMembership
|
|
{
|
|
StudentId = Guid.NewGuid(), GroupId = source.Id, Period = MembershipPeriod.H2Only,
|
|
JoinedAt = new DateOnly(2026, 2, 1), LeftAt = new DateOnly(2026, 7, 31), Niveau = Niveau.E,
|
|
};
|
|
var groups = new MemoryGroups([source]);
|
|
var memberships = new MemoryMemberships([oldMembership]);
|
|
var schemes = new MemorySchemes();
|
|
schemes.Save(new GradingScheme
|
|
{
|
|
GroupId = source.Id, ExamsPercent = 40, ParticipationPercent = 50, OtherPercent = 10,
|
|
});
|
|
var service = new GroupRolloverService(groups, memberships, schemes, new SchoolYearService());
|
|
|
|
var target = service.RollOver(source, new GroupRolloverRequest(
|
|
"9a", "2026/27", 9, [oldMembership.Id], true, true));
|
|
|
|
Assert.Equal("9a", target.Name);
|
|
Assert.Equal(source.SubjectId, target.SubjectId);
|
|
Assert.Equal(source.HoursPerWeek, target.HoursPerWeek);
|
|
Assert.True(target.IsOwnClass);
|
|
Assert.True(target.IsDifferentiated);
|
|
Assert.Null(target.WebUntisLessonId);
|
|
Assert.False(source.IsActive);
|
|
Assert.Equal(source.Id, target.PreviousGroupId);
|
|
|
|
var copied = Assert.Single(memberships.GetByGroup(target.Id));
|
|
Assert.NotEqual(oldMembership.Id, copied.Id);
|
|
Assert.Equal(MembershipPeriod.FullYear, copied.Period);
|
|
Assert.Equal(new DateOnly(2026, 8, 1), copied.JoinedAt);
|
|
Assert.Null(copied.LeftAt);
|
|
Assert.Equal(Niveau.E, copied.Niveau);
|
|
|
|
var scheme = schemes.GetByGroup(target.Id);
|
|
Assert.NotNull(scheme);
|
|
Assert.Equal(40, scheme.ExamsPercent);
|
|
Assert.NotEqual(schemes.GetByGroup(source.Id)!.Id, scheme.Id);
|
|
}
|
|
|
|
[Fact]
|
|
public void RollOver_GleichnamigeGruppeImZieljahr_WirdAbgelehnt()
|
|
{
|
|
var subjectId = Guid.NewGuid();
|
|
var source = new LearningGroup
|
|
{
|
|
Name = "8a", SchoolYear = "2025/26", GradeLevel = 8,
|
|
Type = GroupType.Class, SubjectId = subjectId,
|
|
};
|
|
var existing = new LearningGroup
|
|
{
|
|
Name = "9a", SchoolYear = "2026/27", GradeLevel = 9,
|
|
Type = GroupType.Class, SubjectId = subjectId,
|
|
};
|
|
var membership = new GroupMembership { StudentId = Guid.NewGuid(), GroupId = source.Id };
|
|
var service = new GroupRolloverService(
|
|
new MemoryGroups([source, existing]), new MemoryMemberships([membership]),
|
|
new MemorySchemes(), new SchoolYearService());
|
|
|
|
var error = Assert.Throws<InvalidOperationException>(() => service.RollOver(source,
|
|
new GroupRolloverRequest("9a", "2026/27", 9, [membership.Id], false, false)));
|
|
|
|
Assert.Contains("bereits", error.Message);
|
|
}
|
|
|
|
private sealed class MemoryGroups(List<LearningGroup> items) : IGroupRepository
|
|
{
|
|
public LearningGroup? GetById(Guid id) => items.FirstOrDefault(g => g.Id == id);
|
|
public List<LearningGroup> GetAll(bool includeInactive = false) =>
|
|
items.Where(g => includeInactive || g.IsActive).ToList();
|
|
public List<LearningGroup> GetBySchoolYear(string schoolYear, bool includeInactive = false) =>
|
|
items.Where(g => g.SchoolYear == schoolYear && (includeInactive || g.IsActive)).ToList();
|
|
public void Save(LearningGroup group) { items.RemoveAll(g => g.Id == group.Id); items.Add(group); }
|
|
public void Delete(Guid id) => items.RemoveAll(g => g.Id == id);
|
|
}
|
|
|
|
private sealed class MemoryMemberships(List<GroupMembership> items) : IGroupMembershipRepository
|
|
{
|
|
public List<GroupMembership> GetByStudent(Guid studentId) => items.Where(m => m.StudentId == studentId).ToList();
|
|
public List<GroupMembership> GetByGroup(Guid groupId) => items.Where(m => m.GroupId == groupId).ToList();
|
|
public GroupMembership? GetByStudentAndGroup(Guid studentId, Guid groupId) =>
|
|
items.FirstOrDefault(m => m.StudentId == studentId && m.GroupId == groupId);
|
|
public void Save(GroupMembership membership) { items.RemoveAll(m => m.Id == membership.Id); items.Add(membership); }
|
|
public void Delete(Guid id) => items.RemoveAll(m => m.Id == id);
|
|
}
|
|
|
|
private sealed class MemorySchemes : IGradingSchemeRepository
|
|
{
|
|
private readonly List<GradingScheme> _items = [];
|
|
public GradingScheme? GetByGroup(Guid groupId) => _items.FirstOrDefault(s => s.GroupId == groupId);
|
|
public GradingScheme? GetDefaultForType(GroupType type) => _items.FirstOrDefault(s => s.GroupType == type);
|
|
public void Save(GradingScheme scheme) { _items.RemoveAll(s => s.Id == scheme.Id); _items.Add(scheme); }
|
|
public void Delete(Guid id) => _items.RemoveAll(s => s.Id == id);
|
|
}
|
|
}
|