제 컨트롤러입니다:
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);
}
}
보시다시피 두 개의 종속성, 즉 IDAO
와 ILogger
가 있습니다.
그리고 이것은 내 테스트 클래스이며, 테스트에는 xUnit을 사용하고 모의 및 스텁을 생성하는 데 Moq을 사용하여 DAO
를 쉽게 모의 할 수 있지만 ILogger
를 사용하면 어떻게해야할지 모르겠으므로 테스트를 실행할 때 null을 전달하고 컨트롤러에 로그인하라는 호출을 주석으로 처리합니다. 테스트하면서도 어떻게든 로거를 유지하는 방법이 있을까요?
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());
}
}
다른 종속성과 마찬가지로 조롱하기만 하면 됩니다:
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);
ILogger를 사용하려면
Microsoft.Extensions.Logging.Abstractions` 패키지를 설치해야 할 것입니다.
또한 실제 로거를 만들 수도 있습니다:
var serviceProvider = new ServiceCollection()
.AddLogging()
.BuildServiceProvider();
var factory = serviceProvider.GetService<ILoggerFactory>();
var logger = factory.CreateLogger<BlogController>();
사실, 완벽한 해결책처럼 보이는 'Microsoft.Extensions.Logging.Abstractions.NullLogger'를 발견했습니다.
사용자 정의 로거를 사용하여 (xunit의) ITestOutputHelper
를 사용하여 출력 및 로그를 캡처합니다. 다음은 출력에 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
}
}
추가 제 2 센트,이미지 확장하는 방법이 일반적으로 넣어서 정적 도우미 클래스:
``
개인정보취급방침 MockHelper
{
public static ISetup<ILogger
개인 정적 표현<Action<ILogger
public static void 확인하고 다음,이를 다음과 같이 사용:
//배열
var 로거=새로운 모<ILogger
//Act
//Assert 로거.확인(LogLevel.경고 번입니다.일단()); `` 고의 과정을 쉽게 확장할 수 있다 그것이 모든 기대(즉,은 expection,메시지 등...)
이미 언급할 수 있는 모의로 다른 모든 인터페이스입니다.
var logger = new Mock<ILogger<QueuedHostedService>>();
그래서 지금까지 너무 좋아요.
좋은 것은 사용할 수 있는Moq
을는지 확인하는 특정 전화로 수행되었. 예를 들어 여기에서 내가 있는지 확인은 로그가라는 특별한예외
.
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>>()));
을 사용할 때확인
포인트는 그것에 대하여 실시로그인
방식에서ILooger
인터페이스 및 아 extension 방법이 있습니다.
그것은 쉽게 다른 대답이 제안을 통과하는 모의ILogger
지만,그것은 갑자기 훨씬 더 문제가 있는지 확인하는 통화를 실제로 만들어졌다 logger. 그 이유는 대부분의 통화를하지 않는 실제에 속하는ILogger
인터페이스에 자체입니다.
그래서 대부분의 통화는 확장자를 호출하는 방법에만로그인
방식의 인터페이스입니다. 그 이유는 것은 그것이's 방법으로 쉽게 인터페이스의 구현 하나가있는 경우와 많은 과부는 귀결 같은 방법입니다.
단점은 물론 그것은 갑자기 더 힘들어하는지 확인 전화를 만들어졌기 때문화는지 확인해야 합니다 매우 다르에서 호출됩니다. 거기에 몇 가지 다른 방법이고,내가 찾는 사용자 정의 확장자는 방법에 대한 조롱하는 프레임워크에 그것을 쉽게 작성합니다.
여기에는 예의는 방법을 내가 만든 작품으로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");
그것이 정확하게 보이는 대로 사용한 경우 방법이 바로,트릭은 우리의 확장을 가져옵 우선 순위기 때문에 그것이's"가까이"네임스페이스는 원래보다,그래서 그것을 대신 사용됩니다.
을 제공하지 않는 불행하게도 100%우리가 무엇을 원하는,즉 오류 메시지가 좋지 않을 것입 이후 우리는't 직접 확인에는 문자열이 아니라는 람다를 포함한 문자열하지만,95%is better than nothing:)또한 이러한 접근 방식을 만들 것입 테스트 코드
P.S. 에 대한 Moq 중 하나를 사용할 수 있습의 접근 방식을 쓰는 확장을 위한 방법모<ILogger<T>>
는지확인
을 비슷한 결과를 얻을.
하여 사용하는 경우 StructureMap/라마:
var c = new Container(_ =>
{
_.For(typeof(ILogger<>)).Use(typeof(NullLogger<>));
});
Docs:
https://docs.microsoft.com/en-us/dotnet/api/microsoft.extensions.logging.abstractions.nulllogger?view=aspnetcore-2.1 http://structuremap.github.io/generics/
습니다.net 핵심 3 답변을 사용하는 Moq
-https://stackoverflow.com/a/54646657/2164198 -https://stackoverflow.com/a/54809607/2164198 -https://stackoverflow.com/a/56728528/2164198
가 더 이상 작동하지 않을 변경으로 인해 설명된 문제에서TState 에 ILogger.로그
Lickilystakx제공하는 좋은 해결 방법입니다. 그래서 나는'm 시에 그것을 희망 시간을 절약할 수 있습니다 다른 사람을 위해(그는 그의 것으):
loggerMock.확인( x=>x.로그( LogLevel.정보 니다.IsAny<Id>(), 니다.이<니다.IsAnyType>((o,t)=>문자열입니다.Equals("인덱스 페이지 말 hello",o.ToString(),되기 때문.InvariantCultureIgnoreCase)), 니다.IsAny<예외>(), (Func<니다.IsAnyType,예외,string>)니다.IsAny<object>()), 다.번);