Pregunta

Esto parece algo simple, pero parece que no puedo hacer que funcione.

Tengo una clase con un método Save que simplemente llama a otro método ShouldBeCalled (). Quiero verificar que si llamo a Save () que el otro método shouldBeCalled () se ejecute al menos una vez. Pensé que podía hacer lo siguiente.

public class ClassA
{
    public virtual void Save()
    {
        ShouldBeCalled();
    }

    public virtual void ShouldBeCalled()
    {
        //This should get executed
    }
}

[TestFixture]
public class ClassA_Test
{
    [Test]
    public void Save_Should_Call_ShouldBeCalled()
    {
        var mockClassA = new Mock<ClassA>();
        mockClassA.Object.Save();

        mockClassA.Verify(x => x.ShouldBeCalled(), Times.AtLeastOnce());
    }
}

Pero recibo la excepción " Invocación esperada en el simulacro al menos una vez, pero nunca se realizó: x = > x.ShouldBeCalled () "

Es solo una suposición, pero ¿Moq anula el método Save () con su propia versión que ignora todo lo que tengo dentro del método Save () del objeto real?

¿Fue útil?

Solución

Tiene este problema porque se está burlando de lo que está probando. Esto no tiene sentido.

Tiene razón en que Moq reemplazará la implementación de su método con el suyo propio. La razón es que se supone que debes usar Moq para simular cosas que la clase que estás probando llama, no la clase que estás probando en sí misma.

Esta prueba sería apropiada si su código fue diseñado de esta manera:

public class ClassA
{
    BusinessLogicClass bl;
    public ClassA(BusinessLogicClass bl)
    {
         this.bl = bl;
    }

    public void Save()
    {
        bl.ShouldBeCalled();
    }
}

public class BusinessLogicClass
{
    public virtual void ShouldBeCalled()
    {
        //This should get executed
    }
}

Y aquí está la prueba correcta de ese método ahora:

[TestFixture]
public class ClassA_Test
{
    [Test]
    public void Save_ShouldCallShouldBeCalled()
    {
        //Arrange
        var mockBLClass = new Mock<BusinessLogicClass>();
        mockBLClass.Setup(x => x.ShouldBeCalled()).Verifyable();

        //Act    
        ClassA classA = new ClassA(mockBLClass.Object);
        classA.Save();

        //Assert
        mockBLClass.VerifyAll();
    }
}

La lección clave aquí es que usted se burla / stub de lo que su prueba necesita para ejecutarse , no lo que está probando en sí mismo.

Espero que esto ayude, Anderson

Otros consejos

Intente usar CallBase = true y luego false. Ejecuté tu código y funciona.

var mockClassA = new Mock<ClassA>();
mockClassA.CallBase = true;
mockClassA.Object.Save();
mockClassA.CallBase = false;
mockClassA.Verify(x => x.ShouldBeCalled(), Times.AtLeastOnce());

Sí, esto se puede hacer. Sin embargo, debe agregar una línea de código para que Moq realice un seguimiento de si se llamó o no al método ShouldBeCalled.

Algo como lo siguiente funcionará:

var mockClassA = new Mock<ClassA>();
mockClassA.Setup(x => x.ShouldBeCalled()).Verifiable();    
mockClassA.Object.Save();    
mockClassA.Verify(x => s.ShouldBeCalled(), Times.AtLeastOnce());

El método de configuración establece expectativas. Cuando llama a Verify, le está pidiendo a Moq que verifique estas expectativas. Si no realiza una llamada de instalación para crear expectativas para el método ShouldBeCalled, entonces Moq no considera que se pueda rastrear y, por lo tanto, fallará cuando intente verificarlo.

Puede colocar métodos en el sistema bajo prueba usando CallBase .

[TestFixture]
public class ClassA_Test
{
    [Test]
    public void Save_Should_Call_ShouldBeCalled()
    {
        // Arrange
        var mockClassA = new Mock<ClassA>();
        mockClassA.CallBase = true; // this will call real methods unless the method is mocked/stubbed. 
        mockClassA.Setup(a => a.ShouldBeCalled());

        // Act
        mockClassA.Save();

        // Assert
        mockClassA.Verify(a => a.ShouldBeCalled(), Times.Once());
    }
}
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top