Pruebas unitarias en C# con Moq: verificar llamadas a métodos y excepciones
- Publicado el
- • 2 min de lectura•--- vistas
Moq - es un framework útil que permite simular cualquier funcionalidad provista por el objeto que se está probando. Por ejemplo, necesitas comprobar si algún método fue llamado en un escenario de prueba, y moq te permite hacer eso. Simplemente mockea el método a probar, ejecuta el escenario y detecta si fue llamado al final del escenario de prueba. La documentación oficial y los ejemplos están disponibles aquí - Quickstart. Y también quiero mostrarte algunas funcionalidades que me resultaron útiles. Sigue leyendo. ### Comprobar si un método fue llamado dentro de un objeto.
Por ejemplo, tienes una interfaz de logger y su implementación:
using System;
namespace ...
{
public interface IIntegrationLog
{
void Error(string msg);
void ExecuteWithLogging(Action action);
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.SharePoint;
using Microsoft.SharePoint.Utilities;
...
namespace ...
{
public class IntegrationLog: IIntegrationLog
{
...
public virtual void Error(string msg)
{
Log(Error, msg);
}
public void ExecuteWithLogging(Action action)
{
try
{
action.Invoke();
}
catch (Exception ex)
{
this.Error(ex.Message);
}
}
}
}
La tarea principal es comprobar si el método Error fue llamado dentro y, si lo fue, ¿cuántas veces? Así que escribí una clase de prueba para eso:
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;
namespace ...
{
[TestClass]
public class IntegrationLogTests
{
private Mock<IntegrationLog> _integrationLog;
// mocking testable object:
// implementing method Error() taking string as argument
[TestInitialize]
public void TestInitialize()
{
this._integrationLog = new Mock<IntegrationLog>();
this._integrationLog.Setup(m => m.Error(It.IsAny<string>()));
}
// caller method not twrows any exceptions
// so, => Error not called
[TestMethod]
public void ExecuteWithLogging_ExecuteWithLogging_Successed()
{
this._integrationLog.Object.ExecuteWithLogging(() =>
{
return;
});
this._integrationLog.Verify(m => m.Error(error), Times.Never());
}
// caller throws 1 exception
[TestMethod]
public void ExecuteWithLogging_ExecuteWithLogging_ExceptionCaught()
{
this._integrationLog.Object.ExecuteWithLogging(() =>
{
throw new System.Exception(error);
});
this._integrationLog.Verify(m => m.Error(error), Times.Once());
}
// caller throws 2 exception
[TestMethod]
public void ExecuteWithLogging_ExecuteWithLogging_ExecuteWithLogging2Level()
{
this._integrationLog.Object.ExecuteWithLogging(() =>
{
for (int i = 0; i < 2; i++)
{
this._integrationLog.Object.ExecuteWithLogging(() =>
{
throw new System.Exception(error);
});
}
});
this._integrationLog.Verify(m => m.Error(error), Times.Exactly(2));
}
// caller throws 3 exception
[TestMethod]
public void ExecuteWithLogging_ExecuteWithLogging_ExecuteWithLogging3Level()
{
this._integrationLog.Object.ExecuteWithLogging(() =>
{
for (int i = 0; i < 2; i++)
{
this._integrationLog.Object.ExecuteWithLogging(() =>
{
throw new System.Exception(error);
});
}
throw new System.Exception(error);
});
this._integrationLog.Verify(m => m.Error(error), Times.Exactly(3));
}
}
}
Índice
Disponible para colaboración por contrato
Estoy disponible para colaborar por contrato. Si tiene una idea de proyecto interesante, reserve una llamada por Calendly.
Agenda una llamada de 30 min