Moq: configuração inválida em um membro não substituível: x => x.GetByTitle (“asdf”)

111

Não sei como posso corrigir isso, tentando fazer um teste de unidade no método "GetByTitle"

Aqui estão minhas definições:

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

teste de unidade:

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

Executar o teste me dá o erro:

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

Atualizar

Minha [Setup]aparência é:

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

     _articleManager = new ArticleManager(_mockDaoFactory.Object);    
}
mrblah
fonte
2
Você instancia _mockDaoFactorye em _mockArticleDaoalgum lugar? Você zomba da classe ou da interface
Tomas Aschan
Sim, eu zombei do daofactory e mockarticleDao no [Setup] usando a Interface. o DAO foi feito usando a classe.
mrblah
@tomas Eu atualizei minha pergunta com o código de configuração.
mrblah
2
Como você pode ver na minha resposta, você precisa simular a interface (é o que eu recomendo) ou marcar o GetByTitlemétodo virtual.
Tomas Aschan
Também parece que a primeira linha em seu teste pode ser movida para a rotina de configuração ...?
Tomas Aschan

Respostas:

154

Para controlar o comportamento de um objeto fictício (no Moq, pelo menos), você precisa simular uma interface ou certificar-se de que o comportamento que está tentando controlar está marcado como virtual. Em seu comentário, entendo que a instanciação de _mockArticleDaoseja feita da seguinte forma:

_mockArticleDao = new Mock<ArticleDAO>();

Se quiser mantê-lo assim, você precisa marcar o GetArticlemétodo virtual:

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

Caso contrário (e isso é o que eu recomendo), simule a interface.

_mockArticleDao = new Mock<IArticleDAO>();
Tomas Aschan
fonte
mas uma vez que o ArticleDAO herda de Generic ...., se eu zombar da interface os métodos do GenericNhibern. não será disponibilizado?
mrblah
porque a chamada para GetArticleDAO da fábrica retorna ArticleDAO e não IArticleDAO, b / c articleDAO também se vincula a uma classe abstrata que contém coisas nhibernate.
mrblah
2
Se você não pode simular a interface, então você pode estar testando a coisa errada ... mas ainda assim, marcar o método como virtual resolverá o problema.
Tomas Aschan
+1 Tomas, preciso injetar um parâmetro no ctor, portanto, no meu caso, tive que simular a classe real e definir os métodos como virtuais, porque você não pode injetar parâmetros no ctor de uma interface. É este o caminho certo?
Houman
4
@Kave: Se você precisa injetar algo no construtor, você está definitivamente testando a coisa errada. Zombe de tudo o que você der ao construtor, configure seu comportamento e teste se essa classe se comporta da maneira que deveria. Se precisar, escreva uma nova interface que você faz implementar do tipo "injetado" para acessar todas as assinaturas de método.
Tomas Aschan