Moq: configurazione non valida su un membro non sovrascrivibile: x => x.GetByTitle ("asdf")


111

Non sono sicuro di come posso risolvere questo problema, provando a fare uno unit test con il metodo "GetByTitle"

Ecco le mie definizioni:

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 unitario:

[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'esecuzione del test mi dà l'errore:

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

Aggiornare

Il mio [Setup]aspetto è:

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

     _articleManager = new ArticleManager(_mockDaoFactory.Object);    
}

2
Istanziate _mockDaoFactorye _mockArticleDaoda qualche parte?
Prendi in

Sì, ho deriso daofactory e mockarticleDao in [Setup] usando l'interfaccia. il DAO è stato eseguito utilizzando la classe.
mrblah

@tomas ho aggiornato la mia domanda con il codice di installazione.
mrblah

2
Come puoi vedere nella mia risposta, devi prendere in giro l'interfaccia (è quello che raccomando) o contrassegnare il GetByTitlemetodo virtual.
Tomas Aschan

Sembra anche che la prima riga del test possa essere spostata nella routine di configurazione ...?
Tomas Aschan

Risposte:


154

Per controllare il comportamento di un oggetto fittizio (almeno in Moq), è necessario simulare un'interfaccia o assicurarsi che il comportamento che si sta tentando di controllare sia contrassegnato come virtuale. Nel tuo commento, lo capisco in modo che l'istanza di _mockArticleDaosia eseguita in questo modo:

_mockArticleDao = new Mock<ArticleDAO>();

Se vuoi mantenerlo così, devi contrassegnare il GetArticle metodo virtual:

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

Altrimenti (e questo è quello che consiglio), deridi invece l'interfaccia.

_mockArticleDao = new Mock<IArticleDAO>();

ma poiché ArticleDAO eredita da Generic ...., se derido l'interfaccia i metodi nel GenericNhibern. non sarà reso disponibile?
mrblah

poiché la chiamata a GetArticleDAO dalla fabbrica restituisce ArticleDAO non IArticleDAO, b / c articleDAO si lega anche a una classe astratta che contiene roba nhibernate.
mrblah

2
Se non puoi deridere l'interfaccia, allora potresti provare la cosa sbagliata ... ma comunque, contrassegnare il metodo virtuale risolverà il problema.
Tomas Aschan

+1 Tomas, ho bisogno di iniettare un parametro nel ctor, quindi nel mio caso ho dovuto prendere in giro la classe effettiva e impostare i metodi su virtual, perché non puoi iniettare parametri in un ctor dell'interfaccia. È questo l'approccio giusto?
Houman

4
@ Kave: Se hai bisogno di iniettare qualcosa nel costruttore, stai sicuramente testando la cosa sbagliata. Prendi in giro qualsiasi cosa tu dia al costruttore, imposta il suo comportamento e verifica che questa classe si comporti come dovrebbe. Se necessario, scrivi una nuova interfaccia che implementi il ​​tipo "iniettato" per accedere a tutte le firme del metodo.
Tomas Aschan
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.