es.davy.ai

Preguntas y respuestas de programación confiables

¿Tienes una pregunta?

Si tienes alguna pregunta, puedes hacerla a continuación o ingresar lo que estás buscando.

Burlarse de una interfaz perezosa resultará en una excepción en tiempo de ejecución.

Estoy teniendo dificultades al intentar simular correctamente una interfaz arbitraria envuelta dentro de una clase Lazy.

He intentado lo siguiente:

[TestClass]
public class MyFooServiceTests
{
    private Mock<><ifoo>> _lazyFooMock = new Mock<><ifoo>>();
    private Mock<ifoo> _fooMock = new Mock<ifoo>();
    private MyFooService _service;

    [TestMethod]
    public void FooMethod_HappyPath_ShouldReturn()
    {
        //Arrange
        _fooMock
            .Setup(x => x.DoSomething())
            .Returns(1);

        _lazyFooMock
            .SetupGet(x => x.Value)
            .Returns(_fooMock.Object); // --------> Lanza una excepción.

        _service = new MyService(_lazyFooMock.Object);
    }
}

public interface IFoo
{
    int DoSomething();
}

public class MyFooService
{
    public MyFooService(IFoo foo) { ... }
}

Mensaje de excepción:

Unsupported expression: x => x.Value
No se pueden usar miembros no anulables (aquí: Lazy<ifoo>.get_Value) en expresiones de configuración/verificación.

Moq: 4.16.1

Tags:  , , ,

Answer

  1. Avatar for davy.ai

    Parece que estás obteniendo una excepción al intentar simular una clase Lazy que contiene una interfaz. El mensaje de excepción indica que los miembros no reemplazables, como el método get_Value de la clase Lazy, no se pueden utilizar en expresiones de configuración o verificación.

    Para resolver este problema, puedes crear una nueva interfaz que extienda la clase Lazy<t> y anule la propiedad Value, o puedes utilizar reflexión para establecer el campo privado _valueFactory de la clase Lazy<t> con una instancia simulada de la interfaz.

    Aquí tienes un ejemplo de uso de reflexión:

    [TestClass]
    public class MyFooServiceTests
    {
        private Mock<ifoo> _fooMock = new Mock<ifoo>();
        private MyFooService _service;
    
        [TestMethod]
        public void FooMethod_HappyPath_ShouldReturn()
        {
            // Arrange
            _fooMock
                .Setup(x => x.DoSomething())
                .Returns(1);
    
            var lazyFoo = new Lazy<ifoo>(() => _fooMock.Object);
            var field = typeof(Lazy<ifoo>).GetField("_valueFactory", BindingFlags.Instance | BindingFlags.NonPublic);
            field.SetValue(lazyFoo, (Func<ifoo>)(() => _fooMock.Object));
    
            // Act
            _service = new MyFooService(lazyFoo.Value);
    
            // Assert
            // tus afirmaciones aquí
        }
    }
    

    En este ejemplo, creamos una nueva instancia de la clase Lazy<ifoo> y establecemos su campo _valueFactory en una lambda que devuelve nuestra instancia simulada de la interfaz IFoo. Luego pasamos esta instancia lazy al constructor de MyFooService y continuamos con nuestra prueba.

    Ten en cuenta que ya no necesitamos simular la clase Lazy<ifoo> ya que hemos creado manualmente una instancia con nuestra instancia simulada de IFoo.

Comments are closed.