Für alle, eine Antwort auf diese Frage benötigen, anstatt eine Arbeit um, erweiterte ich die Arbeit dieses Artikels:
https://ardalis.com/testing-logging-in-aspnet-core
Wrap ein Teil des Logging-Framework, die Sie verwenden, die a gute Idee sowieso. Beginnen Sie mit Ihrem eigenen Logging-Schnittstelle:
public interface ILog<T>
{
void LogError(Exception ex, string message, params object[] args);
void LogInformation(string message, params object[] args);
}
dann die Implementierung hinzuzufügen durch Aufrufe an den Rahmen weitergeben müssen:
public class Log<T> : ILog<T>
{
private readonly ILogger<T> logger;
public Log(ILogger<T> logger)
{
this.logger = logger;
}
public void LogError(Exception ex, string message, params object[] args) => this.logger.LogError(ex, message, args);
public void LogInformation(string message, params object[] args) => this.logger.LogInformation(message, args);
}
Umzug auf, fügen Sie eine Schnittstelle zum Einwickeln des Loggers Fabrik:
public interface ILogFactory
{
ILog<T> CreateLog<T>();
}
Und die Umsetzung:
public class LogFactory : ILogFactory
{
private readonly ILoggerFactory loggerFactory;
public LogFactory()
{
this.loggerFactory = new LoggerFactory();
}
public ILog<T> CreateLog<T>() => new Log<T>(new Logger<T>(this.loggerFactory));
}
Dies sind die einzigen Stellen, an denen Sie auf den Namespace Microsoft.Extensions.Logging
verweisen sollten. Verwenden Sie andernfalls ILog<T>
anstelle von ILogger<T>
und ILogFactory
anstelle von ILoggerFactory
. Wo würden Sie normalerweise Abhängigkeit LoggerFactory
injizieren, spritzen, statt den Wrapper:
IServiceCollection serviceCollection = new ServiceCollection();
serviceCollection.AddSingleton<ILogFactory>(new LogFactory());
In Ihrem Haupt-Code können Sie diese LogFactory
abrufen und erstellen Sie Ihre spezifischen Log<T>
für Ihre Klasse:
public class MyClass
{
public void MyMethod(IServiceCollection serviceCollection)
{
var serviceProvider = serviceCollection.BuildServiceProvider();
var logFactory = this.serviceProvider.GetRequiredService<ILogFactory>();
var log = logFactory.CreateLog<ServiceApplication>();
log.LogInformation("Hello, World!");
}
}
Sie sich vorstellen, die sich wandelnde kann Parameter von MyMethod
von IServiceCollection
zu ILogFactory
oder ein ILog<MyClass>
wie erforderlich. Und - der springende Punkt ist - Sie jetzt den obigen Code mit verspotten:
[Fact]
public void Test()
{
IServiceCollection serviceCollection = new ServiceCollection();
var mockLog = new Mock<ILog<MyClass>>();
var mockLogFactory = new Mock<ILogFactory>();
mockLogFactory.Setup(f => f.CreateLog<MyClass>()).Returns(mockLog.Object);
serviceCollection.AddSingleton<ILogFactory>(mockLogFactory.Object);
var myClass = new MyClass();
myClass.MyMethod(serviceCollection);
mockLog.Verify(l => l.LogInformation("Hello, World!"), Times.Once);
}
„Je nach Typen, die Sie haben keine Kontrolle der gesamten Anwendung Kopplung ergänzt und wird häufig eine Quelle von Problemen und technischen Schulden.“ - Steve Smith
Normalerweise injizieren wir 'ILogger' zum Controller. Was ist der Grund für die Injektion von "ILoggerFactory"? –
Win
Ich kann es versuchen. Wird es die Erweiterungsmethode nicht verwenden und daher immer noch fehlschlagen? –
Es funktioniert! Wenn ich das injizierte Objekt in ILogger ändere, kann ich den Logger mit "var mockLogger = new Mock >();" und dann mockLogger.Object in den Test-Controller übergeben. Wenn du @Win eine Antwort postest, würde ich mich freuen zu akzeptieren. –