Тестирование внутренних компонентов метода с помощью RhinoMock или Moq - PullRequest
2 голосов
/ 17 декабря 2009

Совершенно новый для этой насмешливой вещи, у меня есть пара вопросов.

Поправь меня, если я ошибаюсь: Mocking не инициализирует реальный метод, т. Е. Mocking фактически не вызовет конструктор вашего класса. Вместо этого он делает что-то вроде просмотра подписи класса и создания объекта с этой подписью, но без функциональности методов. Это полезно, если вам просто нужен объект этого типа, но вы не хотите проверять его внутренности, например, если объект, который вы на самом деле тестируете, зависит от него.

Я пытаюсь проверить внутреннюю часть метода, значит ли это, что я должен создать экземпляр класса, к которому принадлежит метод?

1 Ответ

7 голосов
/ 17 декабря 2009

Сводка : Динамические макеты не помогут вам протестировать внутренности ваших типов, но вы не должны пытаться делать это в первую очередь.


Вы в основном правы в своем описании, но это немного сложнее. По сути, динамические макеты не делают ничего, что вы не могли бы сделать вручную .

Допустим, вы программируете с использованием такого интерфейса, как этот:

public interface IMyInterface
{
    string Foo(string s);
}

Вы можете вручную создать специфичную для теста реализацию IMyInterface, которая игнорирует входной параметр и всегда возвращает один и тот же вывод:

public class MyClass : IMyInterface
{
    public string Foo(string s)
    {
        return "Bar";
    }
}

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

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

Вот как вы можете определить то же поведение, что и MyClass с Moq:

var mock = new Mock<IMyInterface>();
mock.Setup(x => x.Foo(It.IsAny<string>())).Returns("Bar");

В обоих случаях конструктор созданного класса будет вызываться при создании объекта. Поскольку интерфейс не имеет конструктора, он обычно будет конструктором по умолчанию (MyClass и динамически создаваемый класс соответственно).

Вы можете сделать то же самое с конкретными типами, такими как этот:

public class MyBase
{
    public virtual string Ploeh()
    {
        return "Fnaah";
    }
}

Вручную, вы сможете извлечь из MyBase и переопределить метод Ploeh, потому что он виртуальный:

public class TestSpecificChild : MyBase
{
    public override string Ploeh()
    {
        return "Ndøh";
    }
}

Динамическая фиктивная библиотека может делать то же самое, и то же самое верно для абстрактных методов. В этом случае будет вызываться конструктор базового класса , потому что так работает .NET.

Однако вы не можете написать код, который переопределяет не виртуальный или внутренний элемент, и ни один не может динамически имитировать. Они могут делать только то, что вы можете делать вручную.

Совет: Только модульное тестирование внутренних участников через ваш публичный API .

Предостережение: приведенное выше описание верно для большинства динамических макетов, за исключением TypeMock, который отличается и ... страшен.

...