← Volver al blog

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

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