Usando Moq para determinar si un método se llama

159

Entiendo que puedo probar que se producirá una llamada al método si llamo a un método de nivel superior, es decir:

public abstract class SomeClass()
{    
    public void SomeMehod()
    {
        SomeOtherMethod();
    }

    internal abstract void SomeOtherMethod();
}

Quiero probar que si llamo SomeMethod(), espero que SomeOtherMethod()se llame.

¿Estoy en lo cierto al pensar que este tipo de prueba está disponible en un marco burlón?

Owen
fuente

Respuestas:

186

Puede ver si se ha llamado a un método en algo de lo que se ha burlado utilizando Verificar, por ejemplo:

static void Main(string[] args)
{
        Mock<ITest> mock = new Mock<ITest>();

        ClassBeingTested testedClass = new ClassBeingTested();
        testedClass.WorkMethod(mock.Object);

        mock.Verify(m => m.MethodToCheckIfCalled());
}

class ClassBeingTested
{
    public void WorkMethod(ITest test)
    {
        //test.MethodToCheckIfCalled();
    }
}

public interface ITest
{
    void MethodToCheckIfCalled();
}

Si la línea se deja comentada, lanzará una MockException cuando llame a Verificar. Si no está comentado, pasará.

Pablo
fuente
77
Esta es la respuesta correcta. Debes entender algo, sin embargo. NO PUEDE burlarse de un método / propiedad que no sea abstracto o virtual (obviamente, todos los métodos y propiedades de la interfaz pueden ser burlados).
25
-1: .Expect (...). Verificable () es redundante en este código. Usando AAA, la verificación que tienes es la correcta. .Verificable es para uso con .Verify () i, .e. La versión sin argumentos. Ver stackoverflow.com/questions/980554/…
Ruben Bartelink el
@ I-- yes it can
reggaeguitar
6

No, las pruebas simuladas suponen que está utilizando ciertos patrones de diseño comprobables, uno de los cuales es la inyección. En su caso, estaría probando SomeClass.SomeMethod y SomeOtherMethoddebe implementarse en otra entidad que necesita ser interconectada.

Tu Someclassconstructor se vería así New(ISomeOtherClass). Luego, se burlaría de él ISomeOtherClassy establecería la expectativa SomeOtherMethodpara que se llame y verificara la expectativa.

Val
fuente
0

Aunque estoy de acuerdo en que la respuesta de @ Paul es el camino recomendado, solo quiero agregar un camino alternativo proporcionado por moquno mismo.

Dado que SomeClasses abstractde hecho es mockable, pero public void SomeMehod()no lo es. El punto es encontrar la manera de burlarse y de alguna manera invocar ese método y luego usar CallBasepropagar la llamada al SomeOtherMethod(). Puede sonar como un truco, pero en esencia es simple. Podría usarse en el caso si la refactorización propuesta no es posible.

// This class is used only for test and purpose is make SomeMethod mockable
public abstract class DummyClass : SomeClass
{
    public virtual void DummyMethod() => base.SomeMethod();
}

Luego, puede configurar DummyMethod()para propagar la llamada configurando el CallBaseindicador.

//Arrange
var mock = new Mock<DummyClass>();
mock.Setup(m => m.DummyMethod()).CallBase();

//Act
mock.Object.SomeMethod();

//Assert
mock.Verify(m => m.SomeOtherMethod(), Times.Once);
Johnny
fuente
Votado en contra porque es más complicado y requiere una plantilla
repetitiva
votó porque a veces no puede refactorizar y necesita probar la implementación tal como está
wickdninja