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

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

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
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.