在 C# 中使用 ILogger 对静态方法进行单元测试 ILoggerFactory is Null
Unit Testing Static Methods with ILogger in C# ILoggerFactory is Null
各位,
我正在尝试对我的代码进行单元测试,但是我无法让 ILoggerFactory 工作
这是我的单元测试代码(可能不正确):
using NUnit.Framework;
using Microsoft.Extensions.Logging;
using System.Reflection;
using Moq;
using System;
using MyProgramVIP.Bots.Presenter;
using MyProgramVIP.Bots.Model;
using MyProgramVIP.Bots.Utils;
namespace MyProgramVIPTest
{
public class TestsExample
{
[SetUp]
public void Setup() {
}
[Test]
public void TestExample1()
{
//Mocks
var mockLogger = new Mock<ILogger<TicketPresenter>>();
mockLogger.Setup(
m => m.Log(
LogLevel.Information,
It.IsAny<EventId>(),
It.IsAny<object>(),
It.IsAny<Exception>(),
It.IsAny<Func<object, Exception, string>>()));
var mockLoggerFactory = new Mock<ILoggerFactory>();
mockLoggerFactory.Setup(x => x.CreateLogger(It.IsAny<string>())).Returns(() => mockLogger.Object);
//Construción del modelo necesario para la prueba
ConversationData conversationData = new ConversationData();
conversationData.ticket = new Ticket();
conversationData.response = new Response();
//Invocación del método a probar
TicketPresenter.getPutTicketMessage(conversationData);
//Comprobación del funcionamineto
Assert.AreEqual("ticketType", conversationData.response.cardIdResponse);
}
}
}
这是我要测试的class的代码(我只留下失败的代码行)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json.Linq;
using MyProgramVIP.Bots.Interactor.Services;
using MyProgramVIP.Bots.Model;
using MyProgramVIP.Bots.Utils;
namespace MyProgramVIP.Bots.Presenter
{
public class TicketPresenter
{
private static ILogger _logger = UtilsVIP.ApplicationLogging.CreateLogger(MethodBase.GetCurrentMethod().DeclaringType.Name);
/// <summary>
/// Función getPutTicketMessage: encargada de comenzar con el flujo de poner un ticket.
/// </summary>
/// <param name="conversationData"></param>
public static void getPutTicketMessage(ConversationData conversationData)
{
try
{
//Here it crash.
_logger.LogInformation("INIT getPutTicketMessage");
//Code..........
//Never gets here.
_logger.LogInformation("ENDED getPutTicketMessage");
}
catch (Exception ex)
{
//Here it crash too.
_logger.LogError("EXCEPTION getPutTicketMessage" + ex.ToString());
}
}
}
这是帮助class的代码,正是错误所在:
using System;
using System.Collections.Generic;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json.Linq;
using MyProgramVIP.Bots.Model;
using MyProgramVIP.Bots.Model.Elements;
namespace MyProgramVIP.Bots.Utils
{
public class UtilsVIP
{
private static ILogger _logger = ApplicationLogging.CreateLogger("ILogger");
//Other funtions...
public static class ApplicationLogging
{
public static ILoggerFactory LoggerFactory { get; set; }
public static ILogger CreateLogger<T>() => LoggerFactory.CreateLogger<T>();
//Here LoggerFactory is null.
public static ILogger CreateLogger(string categoryName) => LoggerFactory.CreateLogger("VIPLog: " + categoryName);
}
//Other funtions...
}
}
就在它运行的那一行:
LoggerFactory.CreateLogger("VIPLog: " + categoryName);
LoggerFactory 为空。
我在 Internet 上做了很多研究,但是这些都导致了非静态 class 信息。
万一它很重要,它是一个 Botframework 项目。
如有任何帮助,我们将不胜感激。
提前致谢。
非常感谢@ChetanRanpariya 的评论,我的问题的答案非常简单:
using NUnit.Framework;
using Microsoft.Extensions.Logging;
using System.Reflection;
using Moq;
using System;
using MyProgramVIP.Bots.Presenter;
using MyProgramVIP.Bots.Model;
using MyProgramVIP.Bots.Utils;
namespace MyProgramVIPTest
{
public class TestsExample
{
[SetUp]
public void Setup() {
}
[Test]
public void TestExample1()
{
//Mocks
var mockLogger = new Mock<ILogger<TicketPresenter>>();
mockLogger.Setup(
m => m.Log(
LogLevel.Information,
It.IsAny<EventId>(),
It.IsAny<object>(),
It.IsAny<Exception>(),
It.IsAny<Func<object, Exception, string>>()));
var mockLoggerFactory = new Mock<ILoggerFactory>();
mockLoggerFactory.Setup(x => x.CreateLogger(It.IsAny<string>())).Returns(() => mockLogger.Object);
//Just add this, I guess is replacing the objet with the mock.
UtilsVIP.ApplicationLogging.LoggerFactory = mockLoggerFactory.Object;
//Construción del modelo necesario para la prueba
ConversationData conversationData = new ConversationData();
conversationData.ticket = new Ticket();
conversationData.response = new Response();
//Invocación del método a probar
TicketPresenter.getPutTicketMessage(conversationData);
//Comprobación del funcionamineto
Assert.AreEqual("ticketType", conversationData.response.cardIdResponse);
}
}
}
只需添加:
UtilsVIP.ApplicationLogging.LoggerFactory = mockLoggerFactory.Object;
感谢您的帮助。
这里的例子说明了如何使用 Moq 验证日志是否在 ILogger 上被调用。
_loggerMock.Verify
(
l => l.Log
(
//Check the severity level
LogLevel.Error,
//This may or may not be relevant to your scenario
It.IsAny<EventId>(),
//This is the magical Moq code that exposes internal log processing from the extension methods
It.Is<It.IsAnyType>((state, t) =>
//This confirms that the correct log message was sent to the logger. {OriginalFormat} should match the value passed to the logger
//Note: messages should be retrieved from a service that will probably store the strings in a resource file
CheckValue(state, LogTest.ErrorMessage, "{OriginalFormat}") &&
//This confirms that an argument with a key of "recordId" was sent with the correct value
//In Application Insights, this will turn up in Custom Dimensions
CheckValue(state, recordId, nameof(recordId))
),
//Confirm the exception type
It.IsAny<NotImplementedException>(),
//Accept any valid Func here. The Func is specified by the extension methods
(Func<It.IsAnyType, Exception, string>)It.IsAny<object>()),
//Make sure the message was logged the correct number of times
Times.Exactly(1)
);
private static bool CheckValue(object state, object expectedValue, string key)
{
var keyValuePairList = (IReadOnlyList<KeyValuePair<string, object>>)state;
var actualValue = keyValuePairList.First(kvp => string.Compare(kvp.Key, key, StringComparison.Ordinal) == 0).Value;
return expectedValue.Equals(actualValue);
}
this article 中有更多上下文。
各位,
我正在尝试对我的代码进行单元测试,但是我无法让 ILoggerFactory 工作
这是我的单元测试代码(可能不正确):
using NUnit.Framework;
using Microsoft.Extensions.Logging;
using System.Reflection;
using Moq;
using System;
using MyProgramVIP.Bots.Presenter;
using MyProgramVIP.Bots.Model;
using MyProgramVIP.Bots.Utils;
namespace MyProgramVIPTest
{
public class TestsExample
{
[SetUp]
public void Setup() {
}
[Test]
public void TestExample1()
{
//Mocks
var mockLogger = new Mock<ILogger<TicketPresenter>>();
mockLogger.Setup(
m => m.Log(
LogLevel.Information,
It.IsAny<EventId>(),
It.IsAny<object>(),
It.IsAny<Exception>(),
It.IsAny<Func<object, Exception, string>>()));
var mockLoggerFactory = new Mock<ILoggerFactory>();
mockLoggerFactory.Setup(x => x.CreateLogger(It.IsAny<string>())).Returns(() => mockLogger.Object);
//Construción del modelo necesario para la prueba
ConversationData conversationData = new ConversationData();
conversationData.ticket = new Ticket();
conversationData.response = new Response();
//Invocación del método a probar
TicketPresenter.getPutTicketMessage(conversationData);
//Comprobación del funcionamineto
Assert.AreEqual("ticketType", conversationData.response.cardIdResponse);
}
}
}
这是我要测试的class的代码(我只留下失败的代码行)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json.Linq;
using MyProgramVIP.Bots.Interactor.Services;
using MyProgramVIP.Bots.Model;
using MyProgramVIP.Bots.Utils;
namespace MyProgramVIP.Bots.Presenter
{
public class TicketPresenter
{
private static ILogger _logger = UtilsVIP.ApplicationLogging.CreateLogger(MethodBase.GetCurrentMethod().DeclaringType.Name);
/// <summary>
/// Función getPutTicketMessage: encargada de comenzar con el flujo de poner un ticket.
/// </summary>
/// <param name="conversationData"></param>
public static void getPutTicketMessage(ConversationData conversationData)
{
try
{
//Here it crash.
_logger.LogInformation("INIT getPutTicketMessage");
//Code..........
//Never gets here.
_logger.LogInformation("ENDED getPutTicketMessage");
}
catch (Exception ex)
{
//Here it crash too.
_logger.LogError("EXCEPTION getPutTicketMessage" + ex.ToString());
}
}
}
这是帮助class的代码,正是错误所在:
using System;
using System.Collections.Generic;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json.Linq;
using MyProgramVIP.Bots.Model;
using MyProgramVIP.Bots.Model.Elements;
namespace MyProgramVIP.Bots.Utils
{
public class UtilsVIP
{
private static ILogger _logger = ApplicationLogging.CreateLogger("ILogger");
//Other funtions...
public static class ApplicationLogging
{
public static ILoggerFactory LoggerFactory { get; set; }
public static ILogger CreateLogger<T>() => LoggerFactory.CreateLogger<T>();
//Here LoggerFactory is null.
public static ILogger CreateLogger(string categoryName) => LoggerFactory.CreateLogger("VIPLog: " + categoryName);
}
//Other funtions...
}
}
就在它运行的那一行:
LoggerFactory.CreateLogger("VIPLog: " + categoryName);
LoggerFactory 为空。
我在 Internet 上做了很多研究,但是这些都导致了非静态 class 信息。
万一它很重要,它是一个 Botframework 项目。
如有任何帮助,我们将不胜感激。
提前致谢。
非常感谢@ChetanRanpariya 的评论,我的问题的答案非常简单:
using NUnit.Framework;
using Microsoft.Extensions.Logging;
using System.Reflection;
using Moq;
using System;
using MyProgramVIP.Bots.Presenter;
using MyProgramVIP.Bots.Model;
using MyProgramVIP.Bots.Utils;
namespace MyProgramVIPTest
{
public class TestsExample
{
[SetUp]
public void Setup() {
}
[Test]
public void TestExample1()
{
//Mocks
var mockLogger = new Mock<ILogger<TicketPresenter>>();
mockLogger.Setup(
m => m.Log(
LogLevel.Information,
It.IsAny<EventId>(),
It.IsAny<object>(),
It.IsAny<Exception>(),
It.IsAny<Func<object, Exception, string>>()));
var mockLoggerFactory = new Mock<ILoggerFactory>();
mockLoggerFactory.Setup(x => x.CreateLogger(It.IsAny<string>())).Returns(() => mockLogger.Object);
//Just add this, I guess is replacing the objet with the mock.
UtilsVIP.ApplicationLogging.LoggerFactory = mockLoggerFactory.Object;
//Construción del modelo necesario para la prueba
ConversationData conversationData = new ConversationData();
conversationData.ticket = new Ticket();
conversationData.response = new Response();
//Invocación del método a probar
TicketPresenter.getPutTicketMessage(conversationData);
//Comprobación del funcionamineto
Assert.AreEqual("ticketType", conversationData.response.cardIdResponse);
}
}
}
只需添加:
UtilsVIP.ApplicationLogging.LoggerFactory = mockLoggerFactory.Object;
感谢您的帮助。
这里的例子说明了如何使用 Moq 验证日志是否在 ILogger 上被调用。
_loggerMock.Verify
(
l => l.Log
(
//Check the severity level
LogLevel.Error,
//This may or may not be relevant to your scenario
It.IsAny<EventId>(),
//This is the magical Moq code that exposes internal log processing from the extension methods
It.Is<It.IsAnyType>((state, t) =>
//This confirms that the correct log message was sent to the logger. {OriginalFormat} should match the value passed to the logger
//Note: messages should be retrieved from a service that will probably store the strings in a resource file
CheckValue(state, LogTest.ErrorMessage, "{OriginalFormat}") &&
//This confirms that an argument with a key of "recordId" was sent with the correct value
//In Application Insights, this will turn up in Custom Dimensions
CheckValue(state, recordId, nameof(recordId))
),
//Confirm the exception type
It.IsAny<NotImplementedException>(),
//Accept any valid Func here. The Func is specified by the extension methods
(Func<It.IsAnyType, Exception, string>)It.IsAny<object>()),
//Make sure the message was logged the correct number of times
Times.Exactly(1)
);
private static bool CheckValue(object state, object expectedValue, string key)
{
var keyValuePairList = (IReadOnlyList<KeyValuePair<string, object>>)state;
var actualValue = keyValuePairList.First(kvp => string.Compare(kvp.Key, key, StringComparison.Ordinal) == 0).Value;
return expectedValue.Equals(actualValue);
}
this article 中有更多上下文。