Testabdeckung Kapitel 13.1 (Tests, Fehlerbehandlung)
Vier neue xUnit-Testprojekte (LehrerApp.Tests, .Data.Tests, .Desktop.Tests, .Sync.Tests) mit zusammen 104 Tests: GradingService, SchoolYearService, Repositories gegen In-Memory-LiteDB, Mitarbeits-Aggregation (3.2), Zeugnisnotenberechnung (2.4) und ConflictResolver. Dabei zwei echte Fehler in der Sync-Schicht gefunden und behoben: - SyncEvent.EventId fehlte [BsonId], wodurch EventQueue.Acknowledge() nie etwas aus der Queue löschte. - ConflictResolver verglich Zeitstempel unterschiedlicher DateTimeKind direkt (LiteDB liefert Local statt Utc zurück), was die Gleichstand- Regel außerhalb von UTC+0 verfälschte. SchoolYearService.CurrentSchoolYear()/RecentSchoolYears() um ein optionales today-Argument erweitert, um den Schuljahreswechsel deterministisch zu testen; LiteDbContext um einen Stream-Konstruktor für In-Memory-Tests.
This commit is contained in:
@@ -0,0 +1,127 @@
|
||||
using LehrerApp.Core.Interfaces;
|
||||
using LehrerApp.Core.Models;
|
||||
|
||||
namespace LehrerApp.Desktop.Tests;
|
||||
|
||||
// Einfache In-Memory-Fakes der Repository-Schnittstellen, damit ViewModel-Tests ohne echte
|
||||
// LiteDB-Anbindung laufen. Bewusst schlank gehalten: nur was die getesteten ViewModels brauchen.
|
||||
|
||||
public class FakeStudents(List<Student> all) : IStudentRepository
|
||||
{
|
||||
public Student? GetById(Guid id) => all.FirstOrDefault(s => s.Id == id);
|
||||
public List<Student> GetAll(bool includeInactive = false) => all;
|
||||
public List<Student> GetByGroup(Guid groupId) => all;
|
||||
public void Save(Student student) { }
|
||||
public void Delete(Guid id) { }
|
||||
}
|
||||
|
||||
public class FakeMemberships(List<GroupMembership> all) : IGroupMembershipRepository
|
||||
{
|
||||
public List<GroupMembership> GetByStudent(Guid studentId) => all.Where(m => m.StudentId == studentId).ToList();
|
||||
public List<GroupMembership> GetByGroup(Guid groupId) => all.Where(m => m.GroupId == groupId).ToList();
|
||||
public GroupMembership? GetByStudentAndGroup(Guid studentId, Guid groupId) =>
|
||||
all.FirstOrDefault(m => m.StudentId == studentId && m.GroupId == groupId);
|
||||
public void Save(GroupMembership membership) { }
|
||||
public void Delete(Guid id) { }
|
||||
}
|
||||
|
||||
public class FakeSessions(List<ParticipationSession> all) : IParticipationSessionRepository
|
||||
{
|
||||
public List<ParticipationSession> GetByGroup(Guid groupId) => all.Where(s => s.GroupId == groupId).ToList();
|
||||
public ParticipationSession? GetById(Guid id) => all.FirstOrDefault(s => s.Id == id);
|
||||
public void Save(ParticipationSession session) { }
|
||||
public void Delete(Guid id) { }
|
||||
}
|
||||
|
||||
public class FakeEntries : IParticipationRepository
|
||||
{
|
||||
private readonly List<ParticipationEntry> _all = [];
|
||||
public void Add(ParticipationEntry e) => _all.Add(e);
|
||||
public List<ParticipationEntry> GetBySession(Guid sessionId) => _all.Where(e => e.SessionId == sessionId).ToList();
|
||||
public List<ParticipationEntry> GetByStudent(Guid studentId) => _all.Where(e => e.StudentId == studentId).ToList();
|
||||
public ParticipationEntry? GetBySessionAndStudent(Guid sessionId, Guid studentId) =>
|
||||
_all.FirstOrDefault(e => e.SessionId == sessionId && e.StudentId == studentId);
|
||||
public void Save(ParticipationEntry entry)
|
||||
{
|
||||
_all.RemoveAll(e => e.Id == entry.Id);
|
||||
_all.Add(entry);
|
||||
}
|
||||
public void SaveMany(List<ParticipationEntry> entries) { foreach (var e in entries) Save(e); }
|
||||
public void DeleteBySession(Guid sessionId) => _all.RemoveAll(e => e.SessionId == sessionId);
|
||||
}
|
||||
|
||||
public class FakeAspects : IParticipationAspectRepository
|
||||
{
|
||||
public List<ParticipationAspect> GetDefaults() => [];
|
||||
public List<ParticipationAspect> GetByGroup(Guid groupId) => [];
|
||||
public void Save(ParticipationAspect aspect) { }
|
||||
public void Delete(Guid id) { }
|
||||
}
|
||||
|
||||
public class FakeGrades : IGradeRepository
|
||||
{
|
||||
private readonly List<Grade> _all = [];
|
||||
public void Add(Grade g) => _all.Add(g);
|
||||
public List<Grade> GetByStudentAndGroup(Guid studentId, Guid groupId) =>
|
||||
_all.Where(g => g.StudentId == studentId && g.GroupId == groupId).ToList();
|
||||
public List<Grade> GetByGroup(Guid groupId) => _all.Where(g => g.GroupId == groupId).ToList();
|
||||
public void Save(Grade grade)
|
||||
{
|
||||
_all.RemoveAll(g => g.Id == grade.Id);
|
||||
_all.Add(grade);
|
||||
}
|
||||
public void Delete(Guid id) => _all.RemoveAll(g => g.Id == id);
|
||||
}
|
||||
|
||||
public class FakeExams(List<Exam> all) : IExamRepository
|
||||
{
|
||||
public Exam? GetById(Guid id) => all.FirstOrDefault(e => e.Id == id);
|
||||
public List<Exam> GetByGroup(Guid groupId) => all.Where(e => e.GroupId == groupId).ToList();
|
||||
public void Save(Exam exam) { }
|
||||
public void Delete(Guid id) { }
|
||||
}
|
||||
|
||||
public class FakeResults : IExamResultRepository
|
||||
{
|
||||
private readonly List<ExamResult> _all = [];
|
||||
// Upsert-Semantik nach ExamId+StudentId, wie der reale unique Index es erzwingt.
|
||||
public void Add(ExamResult r)
|
||||
{
|
||||
_all.RemoveAll(x => x.ExamId == r.ExamId && x.StudentId == r.StudentId);
|
||||
_all.Add(r);
|
||||
}
|
||||
public List<ExamResult> GetByExam(Guid examId) => _all.Where(r => r.ExamId == examId).ToList();
|
||||
public List<ExamResult> GetByStudent(Guid studentId) => _all.Where(r => r.StudentId == studentId).ToList();
|
||||
public ExamResult? GetByExamAndStudent(Guid examId, Guid studentId) =>
|
||||
_all.FirstOrDefault(r => r.ExamId == examId && r.StudentId == studentId);
|
||||
public void Save(ExamResult result) { }
|
||||
public void SaveMany(List<ExamResult> results) { }
|
||||
}
|
||||
|
||||
public class FakeSchemes : IGradingSchemeRepository
|
||||
{
|
||||
private readonly Dictionary<Guid, GradingScheme> _byGroup = [];
|
||||
private readonly Dictionary<GroupType, GradingScheme> _byType = [];
|
||||
public void SetForGroup(Guid groupId, GradingScheme s) => _byGroup[groupId] = s;
|
||||
public void SetDefault(GroupType type, GradingScheme s) => _byType[type] = s;
|
||||
public GradingScheme? GetByGroup(Guid groupId) => _byGroup.GetValueOrDefault(groupId);
|
||||
public GradingScheme? GetDefaultForType(GroupType type) => _byType.GetValueOrDefault(type);
|
||||
public void Save(GradingScheme scheme) { }
|
||||
public void Delete(Guid id) { }
|
||||
}
|
||||
|
||||
public class FakeReportGrades : IReportGradeRepository
|
||||
{
|
||||
private readonly List<ReportGrade> _all = [];
|
||||
public int SavedCount { get; private set; }
|
||||
public List<ReportGrade> GetByGroup(Guid groupId) => _all.Where(r => r.GroupId == groupId).ToList();
|
||||
public ReportGrade? GetByStudentGroupPeriod(Guid studentId, Guid groupId, string period) =>
|
||||
_all.FirstOrDefault(r => r.StudentId == studentId && r.GroupId == groupId && r.Period == period);
|
||||
public void Save(ReportGrade grade)
|
||||
{
|
||||
_all.RemoveAll(r => r.Id == grade.Id);
|
||||
_all.Add(grade);
|
||||
SavedCount++;
|
||||
}
|
||||
public void Delete(Guid id) => _all.RemoveAll(r => r.Id == id);
|
||||
}
|
||||
Reference in New Issue
Block a user