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>
106 lines
3.5 KiB
C#
106 lines
3.5 KiB
C#
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); }
|
|
}
|
|
}
|