Fehlerbehandlung, Logging und feldbezogene Validierung (Kapitel 13.2)
Zentrale Exception-Behandlung (Dispatcher.UIThread.UnhandledException, AppDomain, TaskScheduler) verhindert Abstürze und protokolliert Fehler über AppLogger in eine rotierende Log-Datei im App-Datenverzeichnis. Toast-Benachrichtigungen zeigen Erfolg/Fehler global an. Alle Dialoge mit Formularfeldern zeigen Validierungsmeldungen jetzt direkt am betroffenen Feld statt in einem Sammel-Label. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,105 @@
|
||||
using LehrerApp.Core.Services;
|
||||
using Xunit;
|
||||
|
||||
namespace LehrerApp.Tests;
|
||||
|
||||
public sealed class AppLoggerTests
|
||||
{
|
||||
[Fact]
|
||||
public void Konstruktor_LegtLogVerzeichnisAn()
|
||||
{
|
||||
using var temp = new TempAppData();
|
||||
|
||||
_ = new AppLogger(temp.Path);
|
||||
|
||||
Assert.True(Directory.Exists(Path.Combine(temp.Path, "logs")));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Info_SchreibtZeileInDieHeutigeLogdatei()
|
||||
{
|
||||
using var temp = new TempAppData();
|
||||
var logger = new AppLogger(temp.Path);
|
||||
|
||||
logger.Info("Anwendung gestartet.");
|
||||
|
||||
var expectedFile = Path.Combine(temp.Path, "logs", $"lehrerapp-{DateTime.Now:yyyy-MM-dd}.log");
|
||||
Assert.True(File.Exists(expectedFile));
|
||||
var content = File.ReadAllText(expectedFile);
|
||||
Assert.Contains("[INFO ]", content);
|
||||
Assert.Contains("Anwendung gestartet.", content);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Error_MitException_SchreibtStapelverfolgungMit()
|
||||
{
|
||||
using var temp = new TempAppData();
|
||||
var logger = new AppLogger(temp.Path);
|
||||
|
||||
try { throw new InvalidOperationException("Testfehler"); }
|
||||
catch (Exception ex) { logger.Error("Etwas ist schiefgelaufen.", ex); }
|
||||
|
||||
var content = File.ReadAllText(Path.Combine(temp.Path, "logs", $"lehrerapp-{DateTime.Now:yyyy-MM-dd}.log"));
|
||||
Assert.Contains("[ERROR]", content);
|
||||
Assert.Contains("Testfehler", content);
|
||||
Assert.Contains("InvalidOperationException", content);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void MehrereEintraege_WerdenAlleAngehaengt()
|
||||
{
|
||||
using var temp = new TempAppData();
|
||||
var logger = new AppLogger(temp.Path);
|
||||
|
||||
logger.Info("Erster Eintrag");
|
||||
logger.Warn("Zweiter Eintrag");
|
||||
logger.Error("Dritter Eintrag");
|
||||
|
||||
var lines = File.ReadAllLines(Path.Combine(temp.Path, "logs", $"lehrerapp-{DateTime.Now:yyyy-MM-dd}.log"));
|
||||
Assert.Equal(3, lines.Length);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Konstruktor_LoeschtLogdateienAelterAlsDieAufbewahrungsfrist()
|
||||
{
|
||||
using var temp = new TempAppData();
|
||||
var logDir = Path.Combine(temp.Path, "logs");
|
||||
Directory.CreateDirectory(logDir);
|
||||
|
||||
var oldFile = Path.Combine(logDir, "lehrerapp-2000-01-01.log");
|
||||
var recentFile = Path.Combine(logDir, $"lehrerapp-{DateTime.Now:yyyy-MM-dd}.log");
|
||||
File.WriteAllText(oldFile, "alt");
|
||||
File.WriteAllText(recentFile, "aktuell");
|
||||
File.SetLastWriteTime(oldFile, DateTime.Now.AddDays(-30));
|
||||
|
||||
_ = new AppLogger(temp.Path);
|
||||
|
||||
Assert.False(File.Exists(oldFile));
|
||||
Assert.True(File.Exists(recentFile));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Konstruktor_BehaeltLogdateienInnerhalbDerAufbewahrungsfrist()
|
||||
{
|
||||
using var temp = new TempAppData();
|
||||
var logDir = Path.Combine(temp.Path, "logs");
|
||||
Directory.CreateDirectory(logDir);
|
||||
|
||||
var recentButOldFile = Path.Combine(logDir, "lehrerapp-recent.log");
|
||||
File.WriteAllText(recentButOldFile, "vor 5 Tagen");
|
||||
File.SetLastWriteTime(recentButOldFile, DateTime.Now.AddDays(-5));
|
||||
|
||||
_ = new AppLogger(temp.Path);
|
||||
|
||||
Assert.True(File.Exists(recentButOldFile));
|
||||
}
|
||||
|
||||
private sealed class TempAppData : IDisposable
|
||||
{
|
||||
public string Path { get; } = System.IO.Path.Combine(
|
||||
System.IO.Path.GetTempPath(), $"lehrerapp-logger-tests-{Guid.NewGuid():N}");
|
||||
|
||||
public TempAppData() => Directory.CreateDirectory(Path);
|
||||
public void Dispose() { if (Directory.Exists(Path)) Directory.Delete(Path, recursive: true); }
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user