Moq: недопустимая настройка для непереопределяемого элемента: x => x.GetByTitle («asdf»)


111

Не знаю, как это исправить, пытаюсь выполнить модульный тест метода GetByTitle.

Вот мои определения:

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

Запуск теста дает мне ошибку:

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

Обновить

Мой [Setup]выглядит так:

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

     _articleManager = new ArticleManager(_mockDaoFactory.Object);    
}

2
Вы создаете экземпляр _mockDaoFactoryи _mockArticleDaoгде-нибудь? Вы издеваетесь над классом или интерфейсом?
Томас Ашан

Да, я издевался над daofactory и mockarticleDao в [Setup] с помощью интерфейса. DAO был выполнен с использованием класса.
mrblah

@tomas Я обновил свой вопрос установочным кодом.
mrblah

2
Как видно из моего ответа, вам нужно либо смоделировать интерфейс (это то, что я рекомендую), либо отметить GetByTitleметод virtual.
Томас Ашан,

Также похоже, что первую строку в вашем тесте можно переместить в процедуру настройки ...?
Томас Ашан,

Ответы:


154

Чтобы контролировать поведение фиктивного объекта (по крайней мере, в Moq), вам нужно либо имитировать интерфейс, либо убедиться, что поведение, которым вы пытаетесь управлять, помечено как виртуальное. В вашем комментарии я понимаю, что создание экземпляра _mockArticleDaoвыполняется примерно так:

_mockArticleDao = new Mock<ArticleDAO>();

Если вы хотите сохранить его таким, вам нужно отметить GetArticleметод virtual:

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

В противном случае (и это то, что я рекомендую) вместо этого имитируйте интерфейс.

_mockArticleDao = new Mock<IArticleDAO>();

но поскольку ArticleDAO наследуется от Generic ...., если я высмеиваю интерфейс, методы в GenericNhibern. не будет доступно?
mrblah

поскольку вызов GetArticleDAO из фабрики возвращает ArticleDAO, а не IArticleDAO, b / c articleDAO также связывается с абстрактным классом, в котором есть материал nhibernate.
mrblah

2
Если вы не можете имитировать интерфейс, возможно, вы тестируете не то ... но, тем не менее, отметка метода виртуальным решит проблему.
Томас Ашан,

+1 Томас, мне нужно ввести параметр в ctor, поэтому в моем случае мне пришлось издеваться над фактическим классом и установить методы виртуальными, потому что вы не можете вводить параметры в ctor интерфейса. Это правильный подход?
Houman

4
@Kave: Если вам нужно что-то вставить в конструктор, вы определенно тестируете не то. Имитируйте все, что вы даете конструктору, настройте его поведение и проверьте, что этот класс ведет себя так, как должен. Если вам нужно, напишите новый интерфейс, который реализует «внедренный» тип, чтобы получить доступ ко всем сигнатурам методов.
Томас Ашан,
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.