Moq: configuración no válida en un miembro no reemplazable: x => x.GetByTitle ("asdf")

111

No estoy seguro de cómo puedo solucionar este problema, intento hacer una prueba unitaria con el método "GetByTitle".

Aquí están mis definiciones:

public class ArticleDAO :  GenericNHibernateDAO(IArticle, int>, IArticleDAO
{
    public IArticle GetByTitle(string title)
    {
        IQuery query = Session.CreateQuery("...")
        return query.UniqueResult<IArticle>();
    }
}

public interface IArticleDAO
{
    IArticle GetByTitle(string title);
}

prueba de unidad:

[Test]
public void can_load_by_title()
{
    _mockDaoFactory.Setup(x => x.GetArticleDao())
                                .Returns(_mockArticleDao.Object);
    _mockArticleDao.Setup(x => x.GetByTitle("some title"))
                                .Returns(article1.Object);

    _articleManager.LoadArticle("some title");

    Assert.IsNotNull(_articleManager.Article);
}

Ejecutar la prueba me da el error:

System.ArgumentException: Invalid setup on a non-overridable member:
x => x.GetByTitle("some title")

Actualizar

Mi [Setup]apariencia es:

[Setup]
public void SetUp()
{
     _mockDaoFactory = new Mock<IDaoFactory>();
     _mockArticleDao = new Mock<ArticleDao>();

     _articleManager = new ArticleManager(_mockDaoFactory.Object);    
}
mrblah
fuente
2
¿Instalas _mockDaoFactoryy en _mockArticleDaoalgún lugar? ¿Te burlas de la clase o de la interfaz?
Tomas Aschan
Sí, me burlé de daofactory y mockarticleDao en la [Configuración] usando la interfaz. el DAO se hizo usando la clase.
mrblah
@tomas Actualicé mi pregunta con el código de configuración.
mrblah
2
Como puede ver en mi respuesta, debe burlarse de la interfaz (eso es lo que recomiendo) o marcar el GetByTitlemétodo virtual.
Tomas Aschan
También parece que la primera línea de su prueba podría moverse a la rutina de configuración ...
Tomas Aschan

Respuestas:

154

Para controlar el comportamiento de un objeto simulado (en Moq, al menos), debe simular una interfaz o asegurarse de que el comportamiento que está tratando de controlar esté marcado como virtual. En su comentario, lo entiendo para que la instanciación de _mockArticleDaose haga algo como esto:

_mockArticleDao = new Mock<ArticleDAO>();

Si desea mantenerlo así, debe marcar el GetArticlemétodo virtual:

public class ArticleDAO :  GenericNHibernateDAO(IArticle, int>, IArticleDAO
{
    public virtual IArticle GetByTitle(string title)
    {
        // ...
    }
}

De lo contrario (y esto es lo que recomiendo), simule la interfaz.

_mockArticleDao = new Mock<IArticleDAO>();
Tomás Aschan
fuente
pero dado que ArticleDAO hereda de Generic ...., si me burlo de la interfaz, los métodos en GenericNhibern. no estará disponible?
mrblah
debido a que la llamada a GetArticleDAO desde la fábrica devuelve ArticleDAO no IArticleDAO, b / c articleDAO también se une a una clase abstracta que contiene cosas nhibernate.
mrblah
2
Si no puede burlarse de la interfaz, es posible que esté probando algo incorrecto ... pero aún así, marcar el método como virtual resolverá el problema.
Tomas Aschan
+1 Tomas, necesito inyectar un parámetro en el ctor, por lo tanto, en mi caso, tuve que burlarme de la clase real y configurar los métodos en virtual, porque no se pueden inyectar parámetros en el ctor de una interfaz. ¿Es este el enfoque correcto?
Houman
4
@Kave: Si necesita inyectar algo en el constructor, definitivamente está probando algo incorrecto. Simula lo que le des al constructor, configura su comportamiento y prueba que esta clase se comporta como debería. Si es necesario, escriba una nueva interfaz que haga que implemente el tipo "inyectado" para acceder a todas las firmas de métodos.
Tomas Aschan