Este es mi 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 puede ver, tengo 2 dependencias, una IDAO
y unaILogger
Y esta es mi clase de prueba, uso xUnit para probar y Moq para crear simulacros y stub, puedo simular DAO
fácilmente, pero con el ILogger
no sé qué hacer, así que simplemente paso nulo y comento la llamada para iniciar sesión en el controlador cuando se ejecuta la prueba. ¿Hay alguna forma de probar pero aún mantener el registrador de alguna manera?
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
. Tiene algunas buenas sugerencias en su entrada de blog y he venido con mi solución que parece resolver la mayoría de los problemas en la respuesta a continuación .Respuestas:
Simplemente burlarse de él, así como de cualquier otra dependencia:
Probablemente necesite instalar el
Microsoft.Extensions.Logging.Abstractions
paquete para usarloILogger<T>
.Además, puede crear un registrador real:
fuente
De hecho, he encontrado la
Microsoft.Extensions.Logging.Abstractions.NullLogger<>
que parece una solución perfecta. Instale el paqueteMicrosoft.Extensions.Logging.Abstractions
, luego siga el ejemplo para configurarlo y usarlo:y prueba unitaria
fuente
Utilice un registrador personalizado que utilice
ITestOutputHelper
(de xunit) para capturar la salida y los registros. La siguiente es una pequeña muestra que solo escribestate
en la salida.Úselo en sus pruebas unitarias como
fuente
ILogger
hará que sea más utilizable. 2) ElBeginScope
no debe regresar por sí mismo, ya que eso significa que cualquier método probado que comience y termine un alcance durante la ejecución eliminará el registrador. En su lugar, cree una clase anidada "ficticia" privada que implementeIDisposable
y devuelva una instancia de eso (luego elimineIDisposable
deXunitLogger
).Para .net core 3 respuestas que usan Moq
https://stackoverflow.com/a/56728528/2164198
ya no funcionan debido a un cambio descrito en el problema TState en ILogger.Log solía ser un objeto, ahora FormattedLogValues
Afortunadamente, stakx proporcionó una buena solución . Así que lo publico con la esperanza de que pueda ahorrar tiempo a otros (tomó un tiempo resolver las cosas):
fuente
Agregando mis 2 centavos, este es un método de extensión auxiliar que generalmente se coloca en una clase auxiliar estática:
Entonces, lo usas así:
Y, por supuesto, puede ampliarlo fácilmente para simular cualquier expectativa (es decir, expectativa, mensaje, etc.)
fuente
ILogger
: gist.github.com/timabell/d71ae82c6f3eaa5df26b147f9d3842ebIt.Is<string>(s => s.Equals("A parameter is empty!"))
Es fácil, como sugieren otras respuestas, aprobar el simulacro
ILogger
, pero de repente se vuelve mucho más problemático verificar que las llamadas se hicieron realmente al registrador. La razón es que la mayoría de las llamadas no pertenecen a laILogger
propia interfaz.Por tanto, la mayoría de las llamadas son métodos de extensión que llaman al único
Log
método de la interfaz. La razón por la que parece es que es mucho más fácil implementar la interfaz si solo tiene una y no muchas sobrecargas que se reducen al mismo método.El inconveniente es, por supuesto, que de repente es mucho más difícil verificar que se ha realizado una llamada, ya que la llamada que debe verificar es muy diferente de la llamada que realizó. Hay algunos enfoques diferentes para solucionar este problema, y he descubierto que los métodos de extensión personalizados para burlarse del marco harán que sea más fácil de escribir.
Aquí hay un ejemplo de un método que he creado para trabajar
NSubstitute
:Y así es como se puede utilizar:
Se ve exactamente como si hubiera usado el método directamente, el truco aquí es que nuestro método de extensión tiene prioridad porque está "más cerca" en los espacios de nombres que el original, por lo que se usará en su lugar.
Desafortunadamente, no da el 100% de lo que queremos, es decir, los mensajes de error no serán tan buenos, ya que no verificamos directamente en una cadena sino en una lambda que involucre la cadena, pero el 95% es mejor que nada :) Además este enfoque hará que el código de prueba
PD Para Moq, uno puede usar el enfoque de escribir un método de extensión para el
Mock<ILogger<T>>
que noVerify
logre resultados similares.PPS Esto ya no funciona en .Net Core 3, consulte este hilo para obtener más detalles: https://github.com/nsubstitute/NSubstitute/issues/597#issuecomment-573742574
fuente
Ya se mencionó que puede simularlo como cualquier otra interfaz.
Hasta aquí todo bien.
Lo bueno es que puede usarlo
Moq
para verificar que se hayan realizado ciertas llamadas . Por ejemplo, aquí verifico que se haya llamado al registro con un archivoException
.Cuando se usa
Verify
el punto es hacerlo contra elLog
método real de laILooger
interfaz y no los métodos de extensión.fuente
Basándose aún más en el trabajo de @ ivan-samygin y @stakx, aquí hay métodos de extensión que también pueden coincidir en la excepción y todos los valores de registro (KeyValuePairs).
Estos funcionan (en mi máquina;)) con .Net Core 3, Moq 4.13.0 y Microsoft.Extensions.Logging.Abstractions 3.1.0.
fuente
Y al usar StructureMap / Lamar:
Documentos:
fuente
La mera creación de una simulación
ILogger
no es muy valiosa para las pruebas unitarias. También debe verificar que se hayan realizado las llamadas de registro. Puede inyectar un simulacroILogger
con Moq, pero verificar la llamada puede ser un poco complicado. Este artículo profundiza en la verificación con Moq.Aquí hay un ejemplo muy simple del artículo:
Verifica que se haya registrado un mensaje de información. Pero, si queremos verificar información más compleja sobre el mensaje como la plantilla del mensaje y las propiedades nombradas, se vuelve más complicado:
Estoy seguro de que podrías hacer lo mismo con otros frameworks de burla, pero la
ILogger
interfaz asegura que es difícil.fuente
Si todavía es real. Manera simple de registrar la salida en pruebas para .net core> = 3
fuente
Utilice Telerik Just Mock para crear una instancia simulada del registrador:
fuente
Intenté burlarme de esa interfaz de Logger usando NSubstitute (y fallé porque
Arg.Any<T>()
requirió un parámetro de tipo, que no puedo proporcionar), pero terminé creando un registrador de prueba (similar a la respuesta de @ jehof) de la siguiente manera:Puede acceder fácilmente a todos los mensajes registrados y hacer valer todos los parámetros significativos proporcionados con ellos.
fuente