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);    
}
mrblah
źródło
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>();
Tomas Aschan
źródło
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,