এএসপি.নেট কোর আইলোগারের সাথে কীভাবে ইউনিট পরীক্ষা করবেন


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 টি নির্ভরতা রয়েছে, a IDAOএবং aILogger

এবং এটি আমার পরীক্ষার ক্লাস, আমি পরীক্ষার জন্য xUnit এবং মক এবং স্টাব তৈরি করতে Moq ব্যবহার করি, আমি 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
ইলিয়া পরামর্শ অনুসারে আপনি একটি মোককে স্টাব হিসাবে ব্যবহার করতে পারেন, আপনি যদি লগিং পদ্ধতিটি নিজেই ডেকেছিলেন তা পরীক্ষা করার চেষ্টা না করে থাকেন। যদি এটি হয় তবে লগারকে ঠাট্টা-বিদ্রূপ করা কাজ করে না এবং আপনি কয়েকটি ভিন্ন পদ্ধতির চেষ্টা করতে পারেন। আমি একটি সংক্ষিপ্ত নিবন্ধ লিখেছি বিভিন্ন পদ্ধতির দেখায়। নিবন্ধটিতে বিভিন্ন বিকল্পের প্রতিটি সহ একটি সম্পূর্ণ গিটহাব রেপো অন্তর্ভুক্ত রয়েছে । শেষ পর্যন্ত, আমার সুপারিশ, বরং 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
কারখানায় ডিবাগ আউটপুট উইন্ডোতে অ্যাডডেবগ () কল করতে লগ করতে: var فরাসি = সার্ভিসপ্রোভাইডার.গেটসোর্সেস <ILoggerFactory> () .এডডবগ ();
স্পটেডম্ন

3
আমি "রিয়েল লগার" পদ্ধতির আরও কার্যকর দেখতে পেলাম!
ড্যানিয়েল

1
আসল লগার অংশটি নির্দিষ্ট পরিস্থিতিতে লোগো কনফিগারেশন এবং লগলভিল পরীক্ষা করার জন্য দুর্দান্ত কাজ করে।
মার্টিন লটারিং

এই পদ্ধতিটি কেবল স্টাবকে অনুমতি দেবে, তবে কলগুলির যাচাইকরণ নয়। আমি আমার সমাধানটি নিয়ে এসেছি যা মনে হয় নীচের উত্তরে যাচাইকরণের মাধ্যমে বেশিরভাগ সমস্যার সমাধান করতে পারে ।
ইলিয়া চেরনমর্ডিক

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

এটি কেবল নেট নেট 2.0 এর জন্য কাজ করছে বলে মনে হচ্ছে, নেট কোর 1.1 নয়।
থার্কিল ভেরজ

3
@ অ্যাডস্পেস, আপনার মন্তব্যটি উত্তরের চেয়ে আরও কার্যকর
জনি 5

এটি কীভাবে কাজ করবে তার একটি উদাহরণ দিতে পারেন? ইউনিট পরীক্ষা করার সময়, আমি লগগুলি আউটপুট উইন্ডোতে প্রদর্শিত হতে চাই, আমি নিশ্চিত না যে এটি এটি করে কিনা।
J86

@ অ্যাডস্পেসে কি এটি স্টার্টআপ.কে যাওয়ার কথা?
রাক্লোস

1
@ আরক্লোস হুম, সার্ভিস
কালেকশনটি

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()
    {
    }
}

আপনার ইউনিটসেটে এটি পছন্দ করুন

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

আমি ইউনিট পরীক্ষার মামলাগুলি সরাসরি ভিএস থেকে চালাচ্ছি আমার
এটির

1
@ মালিক্সাইফুল্লাহ আমি পুনঃশির্পার ব্যবহার করছি। আমাকে বনাম
যিহোফ

1
@ মালিকসাইফুল্লাহ ভিএস এর পরীক্ষার এক্সপ্লোরার একটি পরীক্ষার আউটপুট খোলার জন্য একটি লিঙ্ক সরবরাহ করে। টেস্টএক্সপ্লোরারে আপনার পরীক্ষাটি নির্বাচন করুন এবং নীচে একটি লিঙ্ক রয়েছে
যিহোফ

1
এটি দুর্দান্ত, ধন্যবাদ! একটি দম্পতি পরামর্শ: 1) টাইপ প্যারামিটার ব্যবহার না করায় এটি জেনেরিক হওয়ার দরকার নেই। ন্যায়বিচারটি প্রয়োগ করা ILoggerএটিকে আরও বিস্তৃতভাবে ব্যবহারযোগ্য করে তুলবে। ২) BeginScopeস্বয়ংক্রিয়ভাবে ফিরে আসা উচিত নয়, কারণ এর অর্থ যে কোনও পরীক্ষিত পদ্ধতি যা রান চলাকালীন কোনও সুযোগ শুরু করে এবং লগারের নিষ্পত্তি করবে। পরিবর্তে, ব্যক্তিগত "ডামি" নেস্টেড বর্গ যা কার্যকরী তৈরি IDisposableএবং যে এর একটি দৃষ্টান্ত আসতে (পরে অপসারণ IDisposableথেকে XunitLogger)।
টোবিয়াস জে

27

.Nq কোর 3 উত্তরগুলির জন্য যা মক ব্যবহার করছে

সৌভাগ্য যে 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
টিম Abell

লগ ওয়ার্নিংয়ে আমরা যে স্ট্রিংটি পেরিয়েছি তা চেক করতে কি মক তৈরি করা সম্ভব হবে? উদাহরণস্বরূপ:It.Is<string>(s => s.Equals("A parameter is empty!"))
সেরহাট

এটি অনেক সাহায্য করে। আমার জন্য একটি অনুপস্থিত অংশটি হল আমি কীভাবে এক্স ইউনাইট আউটপুটটিতে লিখি সেই মোকতে কলব্যাক সেটআপ করতে পারি? আমার জন্য কলব্যাক কখনও আঘাত করে না।
ফ্লিপডব্যাট

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% কিছুই তুলনায় ভাল নয় :) অতিরিক্ত এই পদ্ধতির পরীক্ষা কোড করা হবে

গীত MOQ এক জন্য একটি এক্সটেনশন পদ্ধতি লেখার পদ্ধতির ব্যবহার করতে পারেন Mock<ILogger<T>>যে আছে Verifyঅনুরূপ ফলাফল অর্জন করা।

PPS এই আর নেট কোর 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

@ আইভান-সামিগিন এবং @ স্ট্যাকএক্সের কাজকে আরও বাড়িয়ে তোলার জন্য, এখানে এক্সটেনশন পদ্ধতি রয়েছে যা ব্যতিক্রম এবং সমস্ত লগ মানগুলি (কীভ্যালিউপায়ারস) এর সাথেও মেলে।

নেট কোর 3, মোক 4.13.0 এবং মাইক্রোসফ্ট.এক্সটেনশনগুলি.লগিং.অ্যাস্ট্রাকশন 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ইউনিট পরীক্ষার জন্য কেবল একটি ডামি তৈরি করা খুব মূল্যবান নয়। লগিং কলগুলি করা হয়েছিল তাও আপনার যাচাই করা উচিত। আপনি মোকেরILogger সাথে একটি উপহাস ইনজেক্ট করতে পারেন তবে কলটি যাচাই করা কিছুটা জটিল হতে পারে। এই নিবন্ধটি মোকের সাথে যাচাইয়ের বিষয়ে গভীরতায় যায়।

নিবন্ধ থেকে খুব সাধারণ উদাহরণ এখানে:

_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

যদি এখনও একটি বাস্তব। সহজ উপায়। নেট কোর> = 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

আমি এনজিস্টস্টিউটি ব্যবহার করে লগার ইন্টারফেসটিকে উপহাস করার চেষ্টা করেছি (এবং ব্যর্থ হয়েছে কারণ Arg.Any<T>()আমি যে ধরণের প্যারামিটারের প্রয়োজন হয় যা আমি সরবরাহ করতে পারি না), তবে নিম্নলিখিত পরীক্ষায় একটি পরীক্ষার লগার (একইভাবে @ জেহফের উত্তরের অনুরূপ) তৈরি করে শেষ করেছি:

    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;
            }
        }
    }

আপনি সহজেই সমস্ত লগ করা বার্তাগুলি অ্যাক্সেস করতে এবং এর সাথে প্রদত্ত সমস্ত অর্থবোধক পরামিতি জোড় করে দিতে পারেন।

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.