No sé lo suficiente acerca de cómo funciona esto debajo de las sábanas para darle una respuesta técnica sobre por qué ese es el comportamiento, pero creo que puedo ayudarlo con su confusión.
En su ejemplo, está llamando a un método Say(), y está devolviendo el texto esperado. Su expectativa debe no imponer una implementación particular de Say(), es decir, que llama a un método interno llamado Hello() para devolver esa cadena. Es por eso que no pasa la verificación, y también por qué la cadena devuelta es "", es decir, se ha llamado a la implementación real de Hello().
Al hacer que el método Hello sea público, parece que esto ha permitido a Moq interceptar la llamada y utilizar su implementación. Por lo tanto, en este caso la prueba parece pasar. Sin embargo, en este escenario no ha logrado realmente nada útil, porque su prueba dice que cuando llama a Say() el resultado es "Hello World" cuando en realidad el resultado es "".
he reescrito el ejemplo para mostrar cómo yo esperaría Moq a utilizar (no necesariamente definitivo, pero es de esperar clara.
public interface IHelloProvider
{
string Hello();
}
public class TestClass
{
private readonly IHelloProvider _provider;
public TestClass(IHelloProvider provider)
{
_provider = provider;
}
public string Say()
{
return _provider.Hello();
}
}
[TestMethod]
public void WhenSayCallsHelloProviderAndReturnsResult()
{
//Given
Mock<IHelloProvider> mock = new Mock<IHelloProvider>();
TestClass concrete = new TestClass(mock.Object);
//Expect
mock.Setup(x => x.Hello()).Returns("Hello World");
//When
string result = concrete.Say();
//Then
mock.Verify(x => x.Hello(), Times.Exactly(1));
Assert.AreEqual("Hello World", result);
}
En mi ejemplo, he introducido una interfaz a un IHelloProvider. Se le note que no hay implementación de IHelloProvider. Esto es el corazón de lo que estamos tratando de lograr usando una solución de burla.
Estamos tratando de probar una clase (TestClass), que depende de algo externo (IHelloProvider). Si está utilizando Test Driven Development, probablemente no haya escrito un IHelloProvider ye t, pero usted sabe que necesitará uno en algún momento. Sin embargo, en primer lugar, desea que TestClass funcione, en lugar de distraerse. O tal vez IHelloProvider usa una base de datos, o un archivo plano, o es difícil de configurar.
Incluso si tiene un IHelloProvider totalmente funcional, aún está tratando de probar el comportamiento de TestClass, por lo que usar un HelloProvider concreto puede hacer que su prueba sea más propensa a fallar, por ejemplo, si hay un cambio en el comportamiento de HelloProvider, no desea tener que cambiar las pruebas de cada clase que lo usa, solo desea cambiar las pruebas de HelloProvider.
Volviendo al código, ahora tenemos una clase TestClass, que depende de una interfaz IHelloProvider, cuya implementación se proporciona en tiempo de construcción (esto es inyección de dependencia).
El comportamiento de Say() es que llama al método Hello() en IHelloProvider.
Si mira hacia atrás en la prueba, hemos creado un objeto TestClass real, ya que en realidad queremos probar el código que hemos escrito. Creamos un Mock IHelloProvider, y dijimos que esperamos que tenga su método llamado Hello(), y cuando lo haga, devuelva la cadena "Hello World".
Luego llamamos a Say() y verificamos los resultados como antes.
Lo importante es darse cuenta de que no nos interesa el comportamiento de IHelloProvider, por lo que podemos simularlo para facilitar las pruebas. Estamos interesados en el comportamiento de TestClass, por lo que hemos creado un TestClass real, no un simulacro, para que podamos probar su comportamiento real.
Espero que esto haya ayudado a aclarar lo que está pasando.
Votando esto porque el comportamiento ya no está presente en las versiones actuales de Moq. Ahora es capaz de manejar propiedades y métodos no virtuales que son internos. – krillgar
En lugar de rechazarlo (y cualquier respuesta asociada), ¿qué le parece proporcionar el número de versión de Moq que introdujo esta función y haremos las modificaciones correspondientes? Votar hacia abajo realmente no logra nada. La Q y la A siguen siendo válidas para las versiones de Moq que no tienen esta característica. –