189 votes

Comment effectuer des tests unitaires avec ILogger dans ASP.NET Core

C'est mon contrôleur:

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

Comme vous pouvez le voir j'ai 2 dépendances, IDAO et ILogger

Et c'est ma classe de test, j'utilise xUnit de tester et de Moq de créer des maquettes et le talon, je peux maquette DAO facile, mais avec l' ILogger je ne sais pas quoi faire donc je viens de passer la valeur null et commentez l'appel pour vous connecter au contrôleur pour lancer le test. Est-il un moyen de tester, mais encore de maintenir l'enregistreur en quelque sorte ?

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

205voto

Ilya Chumakov Points 9808

Il suffit de s'en moquer ainsi que de toute autre dépendance:

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

Vous devrez probablement installer Microsoft.Extensions.Logging.Abstractions package pour utiliser ILogger<T> .

De plus, vous pouvez créer un véritable enregistreur:

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

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

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

130voto

Amir Shitrit Points 667

En fait, j'ai trouvé Microsoft.Extensions.Logging.Abstractions.NullLogger<> qui semble être une solution parfaite.

44voto

Jehof Points 14720

Utilisez un enregistreur personnalisé qui utilise ITestOutputHelper (de xunit) pour capturer la sortie et les journaux. Voici un petit exemple qui écrit uniquement les state dans la sortie.

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

Utilisez-le dans vos unittests comme

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

6voto

guillem Points 99

Déjà mentionné, vous pouvez en moquer comme de toute autre interface.

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

So far So good.

Bonne chose est que vous pouvez utiliser Moq afin de vérifier que certains appels ont été effectués. Par exemple, ici je vérifie que le journal a été appelée avec un particulier 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>>()));

Lors de l'utilisation d' Verify le point est de le faire contre le réel Log méthode de l' ILooger interface et pas les méthodes d'extension.

3voto

Christoph Lütjen Points 772

Et lors de l'utilisation de StructureMap / Lamar:

var c = new Container(_ =>
{
    _.For(typeof(ILogger<>)).Use(typeof(NullLogger<>));
});

Docs:

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X