Moq: Nieprawidłowa konfiguracja elementu członkowskiego, którego nie można zastąpić: x => x.GetByTitle („asdf”)


111

Nie wiem, jak mogę to naprawić, próbuję wykonać test jednostkowy metody „GetByTitle”

Oto moje definicje:

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

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

Uruchomienie testu daje mi błąd:

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

Aktualizacja

Mój [Setup]wygląd wygląda tak:

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

     _articleManager = new ArticleManager(_mockDaoFactory.Object);    
}

2
Czy tworzysz instancję _mockDaoFactoryi _mockArticleDaogdzieś?
— Kpisz

Tak, wykpiłem z daofactory i mockartykulku SMS w [Setup] za pomocą interfejsu. DAO zostało wykonane przy użyciu klasy.
— mrblah

@tomas Zaktualizowałem moje pytanie kodem instalacyjnym.
— mrblah

2
Jak widać w mojej odpowiedzi, trzeba albo zakpić interfejs (tak polecam), albo zaznaczyć GetByTitlemetodę virtual.
— Tomas Aschan,

Wygląda też na to, że pierwszą linię twojego testu można przenieść do procedury konfiguracji ...?
— Tomas Aschan,

Odpowiedzi:


154

Aby kontrolować zachowanie pozorowanego obiektu (przynajmniej w Moq), musisz albo mockować interfejs, albo upewnić się, że zachowanie, które próbujesz kontrolować, jest oznaczone jako wirtualne. W twoim komentarzu rozumiem to, więc tworzenie instancji _mockArticleDaoodbywa się mniej więcej tak :

_mockArticleDao = new Mock<ArticleDAO>();

Jeśli chcesz go tak zachować, musisz zaznaczyć GetArticlemetodę virtual:

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

W przeciwnym razie (i to właśnie zalecam) zamiast tego zamontuj interfejs.

_mockArticleDao = new Mock<IArticleDAO>();

ale ponieważ ArticleDAO dziedziczy po Generic ...., jeśli kpię z interfejsu metod w GenericNhibern. nie zostaną udostępnione?
— mrblah

ponieważ wywołanie GetArticleDAO z fabryki zwraca ArticleDAO, a nie IArticleDAO, b / c articleDAO również wiąże się z klasą abstrakcyjną, która zawiera elementy nhibernate.
— mrblah

2
Jeśli nie możesz kpić z interfejsu, być może testujesz coś niewłaściwego ... ale mimo to oznaczenie metody wirtualnej rozwiąże problem.
— Tomas Aschan

+1 Tomas, muszę wstrzyknąć parametr do ctora, stąd w moim przypadku musiałem kpić z rzeczywistej klasy i ustawić metody na wirtualne, ponieważ nie można wstrzyknąć parametrów do procesora interfejsu. Czy to właściwe podejście?
— Houman,

4
@Kave: Jeśli chcesz wprowadzić coś do konstruktora, zdecydowanie testujesz niewłaściwą rzecz. Mock cokolwiek podasz konstruktorowi, skonfiguruj jego zachowanie i sprawdź, czy ta klasa zachowuje się tak, jak powinna. Jeśli potrzebujesz, napisz nowy interfejs, który tworzysz implementację typu „wstrzykniętego”, aby uzyskać dostęp do wszystkich sygnatur metod.
— Tomas Aschan,
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.