Este é meu controlador:
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);
}
}
Como você pode ver, tenho 2 dependências, uma IDAO
e umaILogger
E esta é minha classe de teste, eu uso xUnit para testar e Moq para criar mock e stub, posso simular DAO
facilmente, mas com o ILogger
não sei o que fazer, então apenas passo null e comento a chamada para o controlador de login ao executar o teste. Existe uma maneira de testar, mas ainda manter o logger de alguma forma?
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());
}
}
ILogger
. Ele tem algumas boas sugestões em sua postagem do blog e eu vim com minha solução que parece resolver a maioria dos problemas na resposta abaixo .Respostas:
Basta simular isso, bem como qualquer outra dependência:
Você provavelmente terá que instalar o
Microsoft.Extensions.Logging.Abstractions
pacote para usoILogger<T>
.Além disso, você pode criar um registrador real:
fonte
Na verdade, descobri
Microsoft.Extensions.Logging.Abstractions.NullLogger<>
que parece uma solução perfeita. Instale o pacoteMicrosoft.Extensions.Logging.Abstractions
e siga o exemplo para configurá-lo e usá-lo:e teste de unidade
fonte
Use um logger customizado que usa
ITestOutputHelper
(do xunit) para capturar a saída e os logs. A seguir está um pequeno exemplo que grava apenasstate
na saída.Use-o em seus testes de unidade, como
fonte
ILogger
o tornará mais amplamente utilizável. 2) OBeginScope
não deve retornar a si mesmo, pois isso significa que qualquer método testado que inicie e termine um escopo durante a execução descartará o logger. Em vez disso, crie uma classe aninhada "fictícia" privada que implementaIDisposable
e retorna uma instância dela (depois removaIDisposable
deXunitLogger
).Para .net core 3 respostas que usam Moq
https://stackoverflow.com/a/56728528/2164198
não estão mais funcionando devido a uma alteração descrita no problema TState em ILogger.Log costumava ser objeto, agora FormattedLogValues
Felizmente, o stakx forneceu uma boa solução alternativa . Então, estou postando na esperança de economizar tempo para outras pessoas (demorou um pouco para descobrir as coisas):
fonte
Adicionando meus 2 centavos, este é um método de extensão auxiliar normalmente colocado em uma classe auxiliar estática:
Então, você o usa assim:
E, claro, você pode facilmente estendê-lo para zombar de qualquer expectativa (ou seja, expectativa, mensagem, etc ...)
fonte
ILogger
: gist.github.com/timabell/d71ae82c6f3eaa5df26b147f9d3842ebIt.Is<string>(s => s.Equals("A parameter is empty!"))
É fácil como outras respostas sugerem passar simulado
ILogger
, mas de repente se torna muito mais problemático verificar se as chamadas realmente foram feitas para o logger. O motivo é que a maioria das chamadas não pertence realmente àILogger
própria interface.Portanto, a maioria das chamadas são métodos de extensão que chamam apenas
Log
método da interface. O motivo pelo qual parece é que é muito mais fácil fazer a implementação da interface se você tiver apenas uma e não muitas sobrecargas que se resumem ao mesmo método.A desvantagem é que, de repente, fica muito mais difícil verificar se uma chamada foi feita, pois a chamada que você deve verificar é muito diferente da chamada que você fez. Existem algumas abordagens diferentes para contornar isso, e descobri que os métodos de extensão personalizados para a estrutura de simulação tornarão mais fácil escrever.
Aqui está um exemplo de um método que criei para trabalhar
NSubstitute
:E é assim que pode ser usado:
Parece exatamente como se você tivesse usado o método diretamente, o truque aqui é que nosso método de extensão tem prioridade porque é "mais próximo" em namespaces do que o original, então ele será usado em seu lugar.
Infelizmente não dá 100% do que queremos, ou seja, as mensagens de erro não serão tão boas, já que não verificamos diretamente em uma string, mas sim em um lambda que envolve a string, mas 95% é melhor do que nada :) Adicionalmente esta abordagem fará com que o código de teste
PS Para Moq pode-se usar a abordagem de escrever um método de extensão para o
Mock<ILogger<T>>
que fazVerify
para alcançar resultados semelhantes.PPS Isso não funciona mais no .Net Core 3, verifique este tópico para mais detalhes: https://github.com/nsubstitute/NSubstitute/issues/597#issuecomment-573742574
fonte
Já mencionei, você pode simular como qualquer outra interface.
Por enquanto, tudo bem.
O bom é que você pode usar
Moq
para verificar se certas chamadas foram realizadas . Por exemplo, aqui eu verifico se o log foi chamado com um particularException
.Ao usar,
Verify
o objetivo é fazer isso contra oLog
método real daILooger
interface e não contra os métodos de extensão.fonte
Construindo ainda mais o trabalho de @ ivan-samygin e @stakx, aqui estão os métodos de extensão que também podem corresponder na Exceção e em todos os valores de log (KeyValuePairs).
Eles funcionam (na minha máquina;)) com .Net Core 3, Moq 4.13.0 e Microsoft.Extensions.Logging.Abstractions 3.1.0.
fonte
E ao usar StructureMap / Lamar:
Docs:
fonte
A simples criação de um manequim
ILogger
não é muito valiosa para o teste de unidade. Você também deve verificar se as chamadas de registro foram feitas. Você pode injetar uma simulaçãoILogger
com o Moq, mas verificar a chamada pode ser um pouco complicado. Este artigo detalha a verificação com o Moq.Aqui está um exemplo muito simples do artigo:
Ele verifica se uma mensagem de informação foi registrada. Mas, se quisermos verificar informações mais complexas sobre a mensagem, como o modelo de mensagem e as propriedades nomeadas, fica mais complicado:
Tenho certeza de que você poderia fazer o mesmo com outras estruturas de simulação, mas a
ILogger
interface garante que seja difícil.fonte
Se ainda for real. Maneira simples de registrar a saída em testes para .net core> = 3
fonte
Use o Telerik Just Mock para criar uma instância simulada do logger:
fonte
Eu tentei simular aquela interface do Logger usando NSubstitute (e falhei porque
Arg.Any<T>()
requer um parâmetro de tipo, que eu não posso fornecer), mas acabei criando um logger de teste (semelhante à resposta de @ jehof) da seguinte maneira:Você pode acessar facilmente todas as mensagens registradas e afirmar todos os parâmetros significativos fornecidos com ele.
fonte