Moq: configuration non valide sur un membre non remplaçable: x => x.GetByTitle ("asdf")

111

Je ne sais pas comment résoudre ce problème, en essayant de faire un test unitaire sur la méthode "GetByTitle"

Voici mes définitions:

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);
}

Test de l'unité:

[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);
}

L'exécution du test me donne l'erreur:

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

Mettre à jour

Mon [Setup]ressemble à:

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

     _articleManager = new ArticleManager(_mockDaoFactory.Object);    
}
mrblah
la source
2
Est-ce que vous instanciez _mockDaoFactoryet _mockArticleDaoquelque part? Vous moquez-vous de la classe ou de l'interface
Tomas Aschan
Oui, je me suis moqué de la daofactory et de mockarticleDao dans [Setup] en utilisant l'interface. le DAO a été fait en utilisant la classe.
mrblah
@tomas J'ai mis à jour ma question avec le code de configuration.
mrblah
2
Comme vous pouvez le voir dans ma réponse, vous devez soit vous moquer de l'interface (c'est ce que je recommande), soit marquer la GetByTitleméthode virtual.
Tomas Aschan
Il semble également que la première ligne de votre test puisse être déplacée vers la routine de configuration ...?
Tomas Aschan

Réponses:

154

Afin de contrôler le comportement d'un objet fictif (au moins dans Moq), vous devez soit vous moquer d'une interface, soit vous assurer que le comportement que vous essayez de contrôler est marqué comme virtuel. Dans votre commentaire, je le comprends pour que l'instanciation de _mockArticleDaose fasse quelque chose comme ceci:

_mockArticleDao = new Mock<ArticleDAO>();

Si vous souhaitez le conserver tel quel, vous devez marquer la GetArticleméthode virtual:

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

Sinon (et c'est ce que je recommande), moquez-vous plutôt de l'interface.

_mockArticleDao = new Mock<IArticleDAO>();
Tomas Aschan
la source
mais puisque l'ArticleDAO hérite de Generic ...., si je me moque de l'interface, les méthodes du GenericNhibern. ne sera pas disponible?
mrblah
parce que l'appel à GetArticleDAO à partir de l'usine renvoie ArticleDAO et non IArticleDAO, b / c articleDAO se lie également à une classe abstraite qui contient des éléments nhibernate.
mrblah
2
Si vous ne pouvez pas vous moquer de l'interface, alors vous testez peut-être la mauvaise chose ... mais quand même, marquer la méthode virtuelle résoudra le problème.
Tomas Aschan
+1 Tomas, j'ai besoin d'injecter un paramètre dans le ctor, donc dans mon cas, j'ai dû me moquer de la classe réelle et définir les méthodes sur virtual, car vous ne pouvez pas injecter de paramètres dans le ctor d'une interface. Est-ce la bonne approche?
Houman
4
@Kave: Si vous avez besoin d'injecter quelque chose dans le constructeur, vous testez certainement la mauvaise chose. Mock ce que vous donnez au constructeur, configurez son comportement et testez que cette classe se comporte comme elle le devrait. Si vous en avez besoin, écrivez une nouvelle interface que vous faites implémenter de type "injecté" afin d'accéder à toutes les signatures de méthode.
Tomas Aschan le