Как макетировать класс, не имеющий конструктора по умолчанию - PullRequest
0 голосов
/ 06 февраля 2019

Я хочу смоделировать класс без конструктора по умолчанию и вызвать метод внутри него.Этот метод вызывает другой метод того же класса.Я хочу настроить этот второй метод для возврата значения и выполнения оставшейся части первого метода для проверки некоторых результатов.

[Test]
public void TestFunction(){
    int d=0;
    var mockObject = new Mock<Foo>(){MockBehaviour.Default, p, q}; //p and q are parameters for Foo constructor
    mockObject.Setup(x=>x.func2(a,b,c)).Returns(d);
    mockobject.Object.func1();
}


Class Foo{
    public Foo(int x,int y){}

    public virtual int func1(){
       DoSomething;
       func2();
    }

    public virtual int func2(){}
}

Я издеваюсь над Foo, потому что я не хочу, чтобы func2 () выполнялсякогда я проверяю func1 ().Поэтому я настраиваю mockObject, чтобы он возвращал значение для func2 () без его выполнения, когда func1 () вызывает func2 ().

Когда я запускаю этот тестовый пример, я получаю исключение "System.NotSupportedException: у родителя нетконструктор по умолчанию. Конструктор по умолчанию должен быть явно определен. "

Если я вижу mockObject во время отладки контрольного примера, mockObject.Object не инициализируется.Я новичок в модульном тестировании и макете.Может ли кто-нибудь помочь мне, где я иду не так.

Ответы [ 2 ]

0 голосов
/ 06 февраля 2019

Ответ на ваш актуальный вопрос:

Как смоделировать класс, не имеющий конструктора по умолчанию

Вам необходимо использовать другую перегрузку ctor Mock, чтобыаргументы передаются в нестандартный Foo ctor:

  var mockObject = new Mock<Foo>(1, 2);

Однако ваша стратегия тестирования имеет недостатки, и я считаю, что это связано с тем, как вы понимаете Moq для работы.

Моды полезны для упрощения сложных зависимостей того, что вы тестируете - вместо того, чтобы создавать экземпляры, обрабатывая их жизненные циклы, вы их издеваетесь.Это нормально, когда они не влияют на код, который вы активно тестируете (как уже упоминалось в этом вопросе) - это не ваша цель.Поскольку Func2 () тесно связана с реализацией func1 (), то, как код написан сейчас, не существует способа выполнить Func1 () без выполнения Func2 ().

Вы можете изменить сигнатуру функции Func1 () так, чтобы она принимала Func2 () в качестве аргумента - это позволит вам изменить, какая функция будет передана ему во время тестирования (и позволит легко смоделировать поведение Func2 ().Однако вы уже сказали, что это невозможно.

0 голосов
/ 06 февраля 2019

Если вы ответите на вопрос, который вы пишете, вы можете просто предоставить аргументы, как предложено в этой теме:

var mockObject = new Mock<Foo>(MockBehaviour.Default, FooParameters);
mockObject.Setup(x=>x.func2(a,b,c)).Returns(d);
mockobject.Object.func1();

Однако это не очень хорошая идея.Обычно вы не должны издеваться над тестируемой системой.Это может указывать на то, что ваш класс делает слишком много и нуждается в реструктуризации, чтобы сделать ровно одну единственную вещь.

Однако могут быть ситуации, когда у класса есть несколько членов API, которые зависят друг от друга.,Подумайте о цепочке перегрузок, где вы хотите протестировать множественные перегрузки.Конечно, легко написать тест для самой внутренней перегрузки (с большинством параметров).Однако, если вы хотите проверить, правильно ли установлены другие перегрузки для самого внутреннего параметра, вы действительно застряли.

void DoSomething()
{
    var param = ...
    DoSomething(param);
}
void DoSomething(int p)
{
    // the most inner overload
}

Не существует общего правила, как решить эту зависимость.В этих случаях я стараюсь создавать подклассы для моей тестируемой системы и переопределять ее (virtual) элементы пустым телом - это то же самое, что и MOQ для внутреннего использования.

...