ASP.NET कोर में ILogger के साथ यूनिट टेस्ट कैसे करें


128

यह मेरा नियंत्रक है:

public class BlogController : Controller
{
    private IDAO<Blog> _blogDAO;
    private readonly ILogger<BlogController> _logger;

    public BlogController(ILogger<BlogController> logger, IDAO<Blog> blogDAO)
    {
        this._blogDAO = blogDAO;
        this._logger = logger;
    }
    public IActionResult Index()
    {
        var blogs = this._blogDAO.GetMany();
        this._logger.LogInformation("Index page say hello", new object[0]);
        return View(blogs);
    }
}

जैसा कि आप देख सकते हैं कि मेरे पास 2 निर्भरताएं हैं, ए IDAOऔर एILogger

और यह मेरी परीक्षा की कक्षा है, मैं मॉक और स्टब बनाने के लिए टेस्ट और Moq का उपयोग करने के लिए xUnit का उपयोग करता हूं, मैं आसानी से मॉक कर सकता हूं DAO, लेकिन ILoggerमुझे नहीं पता कि मुझे क्या करना है इसलिए मैं अभी पास हूं और कंट्रोलर में लॉग इन करने के लिए कॉल को कमेंट करता हूं। जब परीक्षण चलाते हैं। वहाँ परीक्षण करने के लिए एक रास्ता है, लेकिन अभी भी लकड़हारा किसी भी तरह रखना है?

public class BlogControllerTest
{
    [Fact]
    public void Index_ReturnAViewResult_WithAListOfBlog()
    {
        var mockRepo = new Mock<IDAO<Blog>>();
        mockRepo.Setup(repo => repo.GetMany(null)).Returns(GetListBlog());
        var controller = new BlogController(null,mockRepo.Object);

        var result = controller.Index();

        var viewResult = Assert.IsType<ViewResult>(result);
        var model = Assert.IsAssignableFrom<IEnumerable<Blog>>(viewResult.ViewData.Model);
        Assert.Equal(2, model.Count());
    }
}

1
आप एक स्टब के रूप में एक मॉक का उपयोग कर सकते हैं, जैसा कि इल्या सुझाव देता है, यदि आप वास्तव में यह परीक्षण करने की कोशिश नहीं कर रहे हैं कि लॉगिंग विधि को ही कहा जाता था। अगर ऐसा है, तो लकड़हारे का मज़ाक उड़ाने से काम नहीं चलता है, और आप कुछ अलग तरीकों की कोशिश कर सकते हैं। मैंने एक छोटा लेख लिखा है जिसमें कई तरह के दृष्टिकोण हैं। लेख में विभिन्न विकल्पों में से प्रत्येक के साथ एक पूर्ण GitHub रेपो शामिल है । अंत में, मेरी सिफारिश, बल्कि ILogger <टी> प्रकार के साथ सीधे काम करने से अपने स्वयं के एडाप्टर का उपयोग करने के लिए यदि आप करने में सक्षम हो की जरूरत है
ssmith

जैसा कि @ सस्मिथ ने उल्लेख किया है कि इसके लिए वास्तविक कॉलों की पुष्टि करने में कुछ परेशानियाँ हैं ILogger। उन्होंने अपने ब्लॉगपोस्ट में कुछ अच्छे सुझाव दिए हैं और मैं अपने समाधान के साथ आया हूं जो नीचे दिए गए उत्तर में अधिकांश परेशानियों को हल करने के लिए लगता है ।
इल्या चेर्नोमोर्डिक

जवाबों:


140

बस इसे और साथ ही किसी अन्य निर्भरता का मज़ाक उड़ाएँ:

var mock = new Mock<ILogger<BlogController>>();
ILogger<BlogController> logger = mock.Object;

//or use this short equivalent 
logger = Mock.Of<ILogger<BlogController>>()

var controller = new BlogController(logger);

आपको संभवतः Microsoft.Extensions.Logging.Abstractionsउपयोग करने के लिए पैकेज स्थापित करने की आवश्यकता होगी ILogger<T>

इसके अलावा आप एक वास्तविक लकड़हारा बना सकते हैं:

var serviceProvider = new ServiceCollection()
    .AddLogging()
    .BuildServiceProvider();

var factory = serviceProvider.GetService<ILoggerFactory>();

var logger = factory.CreateLogger<BlogController>();

5
कारखाने में डिबग आउटपुट विंडो कॉल AddDebug () में प्रवेश करने के लिए: var factory = serviceProvider.GetService <ILoggerFactory> ()। AddDebug ();
धब्बेदार

3
मुझे "असली लकड़हारा" दृष्टिकोण अधिक प्रभावी लगा!
डैनियल जुएल

1
असली लकड़हारा हिस्सा भी विशिष्ट परिदृश्यों में LogConfiguration और LogLevel के परीक्षण के लिए महान काम करता है।
मार्टिन लॉट्टरिंग

यह दृष्टिकोण केवल स्टब की अनुमति देगा, लेकिन कॉलों का सत्यापन नहीं। मैं अपने समाधान के साथ आया हूं जो नीचे दिए गए उत्तर में सत्यापन के साथ अधिकांश परेशानियों को हल करने के लिए लगता है ।
इल्या चेर्नोमोर्डिक

102

दरअसल, मैंने पाया है Microsoft.Extensions.Logging.Abstractions.NullLogger<>जो एक सही समाधान की तरह दिखता है। पैकेज स्थापित करें Microsoft.Extensions.Logging.Abstractions, फिर उसे कॉन्फ़िगर और उपयोग करने के लिए उदाहरण का पालन करें:

using Microsoft.Extensions.Logging;

public void ConfigureServices(IServiceCollection services)
{
    ...

    services.AddSingleton<ILoggerFactory, NullLoggerFactory>();

    ...
}
using Microsoft.Extensions.Logging;

public class MyClass : IMyClass
{
    public const string ErrorMessageILoggerFactoryIsNull = "ILoggerFactory is null";

    private readonly ILogger<MyClass> logger;

    public MyClass(ILoggerFactory loggerFactory)
    {
        if (null == loggerFactory)
        {
            throw new ArgumentNullException(ErrorMessageILoggerFactoryIsNull, (Exception)null);
        }

        this.logger = loggerFactory.CreateLogger<MyClass>();
    }
}

और इकाई परीक्षण

//using Microsoft.VisualStudio.TestTools.UnitTesting;
//using Microsoft.Extensions.Logging;

[TestMethod]
public void SampleTest()
{
    ILoggerFactory doesntDoMuch = new Microsoft.Extensions.Logging.Abstractions.NullLoggerFactory();
    IMyClass testItem = new MyClass(doesntDoMuch);
    Assert.IsNotNull(testItem);
}   

यह केवल .NET कोर 2.0 के लिए काम करता है, न कि .NET Core 1.1 के लिए।
थोरिल व्रगे

3
@adospace, आपकी टिप्पणी उत्तर की तुलना में अधिक उपयोगी है
जॉनी 5

क्या आप इस बात का उदाहरण दे सकते हैं कि यह कैसे काम करेगा? जब यूनिट परीक्षण, मैं आउटपुट विंडो में प्रदर्शित होने के लिए लॉग चाहता हूं, मुझे यकीन नहीं है कि यह ऐसा होता है।
J86

@adospace क्या स्टार्टअप में जाना है?
राकोसल

1
@raklos हम नहीं, यह परीक्षण के अंदर एक स्टार्टअप पद्धति में उपयोग किया जाना चाहिए, जहां
सर्विसकॉल का त्वरित मूल्यांकन किया

32

ITestOutputHelperआउटपुट और लॉग को कैप्चर करने के लिए (xunit से) उपयोग करने वाले कस्टम लकड़हारे का उपयोग करें । निम्नलिखित एक छोटा सा नमूना है जो केवल stateआउटपुट पर लिखता है ।

public class XunitLogger<T> : ILogger<T>, IDisposable
{
    private ITestOutputHelper _output;

    public XunitLogger(ITestOutputHelper output)
    {
        _output = output;
    }
    public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func<TState, Exception, string> formatter)
    {
        _output.WriteLine(state.ToString());
    }

    public bool IsEnabled(LogLevel logLevel)
    {
        return true;
    }

    public IDisposable BeginScope<TState>(TState state)
    {
        return this;
    }

    public void Dispose()
    {
    }
}

इसे अपने unittests में उपयोग करें

public class BlogControllerTest
{
  private XunitLogger<BlogController> _logger;

  public BlogControllerTest(ITestOutputHelper output){
    _logger = new XunitLogger<BlogController>(output);
  }

  [Fact]
  public void Index_ReturnAViewResult_WithAListOfBlog()
  {
    var mockRepo = new Mock<IDAO<Blog>>();
    mockRepo.Setup(repo => repo.GetMany(null)).Returns(GetListBlog());
    var controller = new BlogController(_logger,mockRepo.Object);
    // rest
  }
}

1
नमस्ते। यह मेरे लिए ठीक है। अब मैं अपनी लॉग इन जानकारी को कैसे देख या देख सकता हूं
malik saifullah

मैं सीधे वीएस से यूनिट टेस्ट केस चला रहा हूं। मेरे पास उस के लिए सांत्वना नहीं है
malik saifullah

1
@maliksaifullah im resharper का उपयोग करते हुए। मुझे इस बात की जाँच करें कि vs
Jehof

1
@maliksaifullah वीएस की TestExplorer एक परीक्षण के उत्पादन को खोलने के लिए एक लिंक प्रदान करता है। TestExplorer में अपने परीक्षण का चयन करें और नीचे एक लिंक है
Jehof

1
यह बहुत अच्छा है, धन्यवाद! कुछ सुझाव: 1) यह सामान्य होने की आवश्यकता नहीं है, क्योंकि टाइप पैरामीटर का उपयोग नहीं किया जाता है। सिर्फ लागू ILoggerकरने से यह अधिक व्यापक रूप से उपयोग करने योग्य हो जाएगा। 2) BeginScopeअपने आप को वापस नहीं आना चाहिए, क्योंकि इसका मतलब है कि कोई भी परीक्षण किया गया तरीका जो रन के दौरान एक गुंजाइश शुरू और समाप्त होता है, लकड़हारे को नष्ट कर देगा। इसके बजाय, एक निजी "डमी" नेस्टेड वर्ग जो औजार बनाने IDisposableऔर उस का एक उदाहरण वापसी (तब हटाने IDisposableसे XunitLogger)।
टोबियास जे

27

.Net कोर 3 उत्तरों के लिए जो Moq का उपयोग कर रहे हैं

सौभाग्य से stakx ने एक अच्छा समाधान प्रदान किया । इसलिए मैं इसे उम्मीद में पोस्ट कर रहा हूं कि यह दूसरों के लिए समय बचा सकता है (चीजों को समझने में थोड़ा समय लगा):

 loggerMock.Verify(
                x => x.Log(
                    LogLevel.Information,
                    It.IsAny<EventId>(),
                    It.Is<It.IsAnyType>((o, t) => string.Equals("Index page say hello", o.ToString(), StringComparison.InvariantCultureIgnoreCase)),
                    It.IsAny<Exception>(),
                    (Func<It.IsAnyType, Exception, string>) It.IsAny<object>()),
                Times.Once);

आपने मेरा दिन बचाया..धन्यवाद।
किद्दोवलप्टर

15

मेरा 2 सेंट जोड़ना, यह एक सहायक विस्तार विधि है जिसे आम तौर पर एक स्थिर सहायक वर्ग में रखा जाता है:

static class MockHelper
{
    public static ISetup<ILogger<T>> MockLog<T>(this Mock<ILogger<T>> logger, LogLevel level)
    {
        return logger.Setup(x => x.Log(level, It.IsAny<EventId>(), It.IsAny<object>(), It.IsAny<Exception>(), It.IsAny<Func<object, Exception, string>>()));
    }

    private static Expression<Action<ILogger<T>>> Verify<T>(LogLevel level)
    {
        return x => x.Log(level, 0, It.IsAny<object>(), It.IsAny<Exception>(), It.IsAny<Func<object, Exception, string>>());
    }

    public static void Verify<T>(this Mock<ILogger<T>> mock, LogLevel level, Times times)
    {
        mock.Verify(Verify<T>(level), times);
    }
}

फिर, आप इसे इस तरह उपयोग करते हैं:

//Arrange
var logger = new Mock<ILogger<YourClass>>();
logger.MockLog(LogLevel.Warning)

//Act

//Assert
logger.Verify(LogLevel.Warning, Times.Once());

और निश्चित रूप से आप इसे आसानी से किसी भी अपेक्षा का मजाक बनाने के लिए बढ़ा सकते हैं (जैसे कि समाप्ति, संदेश, आदि…)


यह एक बहुत ही सुंदर समाधान है।
माइकलडॉटनॉक्स

मैं सहमत हूं, यह जवाब बहुत अच्छा था। मुझे समझ में नहीं आता कि इसमें
इतने

1
फैब। यहां गैर-जेनेरिक के लिए एक संस्करण दिया गया है ILogger: gist.github.com/timabell/d71ae82c6f3eaa5df26b147f9d3842eb
टिम एबेल

क्या हम LogWarning में पारित स्ट्रिंग की जांच करने के लिए नकली बनाना संभव होगा? उदाहरण के लिए:It.Is<string>(s => s.Equals("A parameter is empty!"))
सेराट

इससे बहुत मदद मिलती है। मेरे लिए एक गायब टुकड़ा यह है कि मैं XUnit आउटपुट को लिखने वाले नकली पर कॉलबैक कैसे सेट कर सकता हूं? मेरे लिए कभी भी कॉलबैक हिट न करें।
फ्लिपडौबट

6

यह आसान है क्योंकि अन्य उत्तर मॉक पास करने का सुझाव देते हैं ILogger, लेकिन यह सत्यापित करने के लिए अचानक बहुत अधिक समस्याग्रस्त हो जाता है कि कॉल वास्तव में लकड़हारे के लिए किए गए थे। कारण यह है कि अधिकांश कॉल वास्तव में ILoggerस्वयं इंटरफ़ेस से संबंधित नहीं हैं ।

तो सबसे कॉल एक्सटेंशन तरीके हैं जो Logइंटरफ़ेस की एकमात्र विधि कहते हैं । कारण यह लगता है कि यह इंटरफ़ेस को लागू करने के लिए आसान है यदि आपके पास सिर्फ एक है और न ही कई अधिभार हैं जो एक ही विधि से उबलते हैं।

दोष यह है कि यह सत्यापित करना बहुत कठिन है कि आपके द्वारा कॉल की गई कॉल को सत्यापित किया जाना चाहिए क्योंकि आपने जो कॉल किया है, उससे बहुत अलग है। इसके आसपास काम करने के लिए कुछ अलग तरीके हैं, और मैंने पाया है कि मॉकिंग फ्रेमवर्क के लिए कस्टम एक्सटेंशन के तरीकों को लिखना आसान होगा।

यहाँ एक विधि का एक उदाहरण है जिसे मैंने काम करने के लिए बनाया है NSubstitute:

public static class LoggerTestingExtensions
{
    public static void LogError(this ILogger logger, string message)
    {
        logger.Log(
            LogLevel.Error,
            0,
            Arg.Is<FormattedLogValues>(v => v.ToString() == message),
            Arg.Any<Exception>(),
            Arg.Any<Func<object, Exception, string>>());
    }

}

और इसका उपयोग इस प्रकार किया जा सकता है:

_logger.Received(1).LogError("Something bad happened");   

यह बिल्कुल वैसा ही दिखता है जैसे आपने सीधे तरीके का इस्तेमाल किया था, यहाँ ट्रिक यह है कि हमारे एक्सटेंशन मेथड को प्राथमिकता मिलती है क्योंकि यह मूल नाम की तुलना में नेमस्पेस में "करीब" है, इसलिए इसका उपयोग इसके बजाय किया जाएगा।

यह दुर्भाग्य से 100% नहीं देता है कि हम क्या चाहते हैं, अर्थात् त्रुटि संदेश उतना अच्छा नहीं होगा, क्योंकि हम सीधे स्ट्रिंग पर जांच नहीं करते हैं, बल्कि एक लैम्ब्डा पर जिसमें स्ट्रिंग शामिल है, लेकिन 95% कुछ भी नहीं से बेहतर है :) इसके अलावा यह दृष्टिकोण परीक्षण कोड बना देगा

PS for Moq एक के लिए एक विस्तार विधि लिखने के दृष्टिकोण का उपयोग कर सकता है Mock<ILogger<T>>जो Verifyसमान परिणाम प्राप्त करने के लिए करता है।

PPS यह .Net Core 3 में काम नहीं करता है, अधिक जानकारी के लिए इस धागे की जाँच करें: https://github.com/nsubstitute/NSubstitute/issues/597#issuecomment-573742574


आप लकड़हारा कॉल क्यों सत्यापित करते हैं? वे व्यावसायिक तर्क का हिस्सा नहीं हैं। यदि कुछ बुरा हुआ है, तो मैं वास्तविक प्रोग्राम व्यवहार (जैसे एक त्रुटि हैंडलर को कॉल करना या अपवाद फेंकना) को सत्यापित करने के लिए संदेश लॉग करने की तुलना में सत्यापित करूंगा।
इल्या चुमाकोव

1
वैसे मुझे लगता है कि यह महत्वपूर्ण है कि कम से कम कुछ मामलों में परीक्षण किया जाए। मैंने कई बार देखा है कि कोई प्रोग्राम चुपचाप विफल हो जाता है, इसलिए मुझे लगता है कि यह सत्यापित करने के लिए समझ में आता है कि लॉगिंग तब हुई जब कोई अपवाद हुआ और यह "या तो" जैसा नहीं है, बल्कि वास्तविक प्रोग्राम व्यवहार और लॉगिंग दोनों का परीक्षण कर रहा है।
इल्या चेर्नोमोर्डिक

5

पहले ही उल्लेख किया गया है कि आप इसे किसी अन्य इंटरफ़ेस के रूप में मॉक कर सकते हैं।

var logger = new Mock<ILogger<QueuedHostedService>>();

अब तक सब ठीक है।

अच्छी बात यह है कि आप यह सत्यापितMoq करने के लिए उपयोग कर सकते हैं कि कुछ कॉल किए गए हैं । उदाहरण के लिए, मैं जाँचता हूँ कि लॉग को किसी विशेष के साथ बुलाया गया है Exception

logger.Verify(m => m.Log(It.Is<LogLevel>(l => l == LogLevel.Information), 0,
            It.IsAny<object>(), It.IsAny<TaskCanceledException>(), It.IsAny<Func<object, Exception, string>>()));

Verifyबिंदु का उपयोग करते समय इसे इंटरफ़ेस Logसे वास्तविक विधि के विरुद्ध करना है ILoogerन कि विस्तार विधियों से।


5

@ Ivan-samygin और @stakx के काम पर और भी आगे बढ़ते हुए, यहां विस्तार विधियां हैं जो अपवाद और सभी लॉग मान (KeyValuePairs) पर भी मेल खा सकती हैं।

ये काम (मेरी मशीन पर;)) .Net Core 3, Moq 4.13.0 और Microsoft.Extensions.Logging.Abstractions 3.1.0 के साथ।

/// <summary>
/// Verifies that a Log call has been made, with the given LogLevel, Message and optional KeyValuePairs.
/// </summary>
/// <typeparam name="T">Type of the class for the logger.</typeparam>
/// <param name="loggerMock">The mocked logger class.</param>
/// <param name="expectedLogLevel">The LogLevel to verify.</param>
/// <param name="expectedMessage">The Message to verify.</param>
/// <param name="expectedValues">Zero or more KeyValuePairs to verify.</param>
public static void VerifyLog<T>(this Mock<ILogger<T>> loggerMock, LogLevel expectedLogLevel, string expectedMessage, params KeyValuePair<string, object>[] expectedValues)
{
    loggerMock.Verify(mock => mock.Log(
        expectedLogLevel,
        It.IsAny<EventId>(),
        It.Is<It.IsAnyType>((o, t) => MatchesLogValues(o, expectedMessage, expectedValues)),
        It.IsAny<Exception>(),
        It.IsAny<Func<object, Exception, string>>()
        )
    );
}

/// <summary>
/// Verifies that a Log call has been made, with LogLevel.Error, Message, given Exception and optional KeyValuePairs.
/// </summary>
/// <typeparam name="T">Type of the class for the logger.</typeparam>
/// <param name="loggerMock">The mocked logger class.</param>
/// <param name="expectedMessage">The Message to verify.</param>
/// <param name="expectedException">The Exception to verify.</param>
/// <param name="expectedValues">Zero or more KeyValuePairs to verify.</param>
public static void VerifyLog<T>(this Mock<ILogger<T>> loggerMock, string expectedMessage, Exception expectedException, params KeyValuePair<string, object>[] expectedValues)
{
    loggerMock.Verify(logger => logger.Log(
        LogLevel.Error,
        It.IsAny<EventId>(),
        It.Is<It.IsAnyType>((o, t) => MatchesLogValues(o, expectedMessage, expectedValues)),
        It.Is<Exception>(e => e == expectedException),
        It.Is<Func<It.IsAnyType, Exception, string>>((o, t) => true)
    ));
}

private static bool MatchesLogValues(object state, string expectedMessage, params KeyValuePair<string, object>[] expectedValues)
{
    const string messageKeyName = "{OriginalFormat}";

    var loggedValues = (IReadOnlyList<KeyValuePair<string, object>>)state;

    return loggedValues.Any(loggedValue => loggedValue.Key == messageKeyName && loggedValue.Value.ToString() == expectedMessage) &&
           expectedValues.All(expectedValue => loggedValues.Any(loggedValue => loggedValue.Key == expectedValue.Key && loggedValue.Value == expectedValue.Value));
}


1

केवल एक डमी बनाना ILoggerइकाई परीक्षण के लिए बहुत मूल्यवान नहीं है। आपको यह भी सत्यापित करना चाहिए कि लॉगिंग कॉल किए गए थे। आप Moq केILogger साथ एक नकली इंजेक्ट कर सकते हैं लेकिन कॉल को सत्यापित करना थोड़ा मुश्किल हो सकता है। यह लेख Moq के साथ पुष्टि करने के बारे में गहराई में जाता है।

यहाँ लेख से एक बहुत ही सरल उदाहरण है:

_loggerMock.Verify(l => l.Log(
LogLevel.Information,
It.IsAny<EventId>(),
It.IsAny<It.IsAnyType>(),
It.IsAny<Exception>(),
(Func<It.IsAnyType, Exception, string>)It.IsAny<object>()), Times.Exactly(1));

यह पुष्टि करता है कि एक सूचना संदेश लॉग किया गया था। लेकिन, यदि हम संदेश के बारे में अधिक जटिल जानकारी जैसे कि संदेश टेम्पलेट और नामित गुणों को सत्यापित करना चाहते हैं, तो यह अधिक मुश्किल हो जाता है:

_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)
);

मुझे यकीन है कि आप अन्य नकली रूपरेखाओं के साथ भी ऐसा कर सकते हैं, लेकिन ILoggerइंटरफ़ेस सुनिश्चित करता है कि यह मुश्किल है।


1
मैं भावना के साथ सहमत हूं, और जैसा कि आप कहते हैं कि यह अभिव्यक्ति का निर्माण करना थोड़ा मुश्किल हो सकता है। मुझे एक ही समस्या थी, अक्सर, इसलिए हाल ही में Moq.Contrib.ExpressionBuilders को एक साथ रखा गया। एक धाराप्रवाह इंटरफ़ेस प्रदान करने के लिए।
rgvlee

1

अगर अभी भी वास्तविक है। .Net कोर> = 3 के लिए परीक्षणों में आउटपुट के लिए सरल तरीका लॉग इन करें

[Fact]
public void SomeTest()
{
    using var logFactory = LoggerFactory.Create(builder => builder.AddConsole());
    var logger = logFactory.CreateLogger<AccountController>();
    
    var controller = new SomeController(logger);

    var result = controller.SomeActionAsync(new Dto{ ... }).GetAwaiter().GetResult();
}


0

मैंने NSubstitute का उपयोग करके उस लकड़हारे इंटरफ़ेस को मॉक करने की कोशिश की है (और असफल हो गया क्योंकि Arg.Any<T>()एक प्रकार के पैरामीटर की आवश्यकता होती है, जिसे मैं प्रदान नहीं कर सकता), लेकिन एक परीक्षण लकड़हारा (जैसे @ jehof के उत्तर) को निम्नलिखित तरीके से बनाना समाप्त किया:

    internal sealed class TestLogger<T> : ILogger<T>, IDisposable
    {
        private readonly List<LoggedMessage> _messages = new List<LoggedMessage>();

        public IReadOnlyList<LoggedMessage> Messages => _messages;

        public void Dispose()
        {
        }

        public IDisposable BeginScope<TState>(TState state)
        {
            return this;
        }

        public bool IsEnabled(LogLevel logLevel)
        {
            return true;
        }

        public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func<TState, Exception, string> formatter)
        {
            var message = formatter(state, exception);
            _messages.Add(new LoggedMessage(logLevel, eventId, exception, message));
        }

        public sealed class LoggedMessage
        {
            public LogLevel LogLevel { get; }
            public EventId EventId { get; }
            public Exception Exception { get; }
            public string Message { get; }

            public LoggedMessage(LogLevel logLevel, EventId eventId, Exception exception, string message)
            {
                LogLevel = logLevel;
                EventId = eventId;
                Exception = exception;
                Message = message;
            }
        }
    }

आप सभी लॉग किए गए संदेशों को आसानी से एक्सेस कर सकते हैं और इसके साथ दिए गए सभी सार्थक मापदंडों को पूरा कर सकते हैं।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.