Чтобы издеваться над объектом, он должен быть либо реализующим интерфейс, либо помеченным как виртуальный?
Или класс может также реализовывать абстрактный класс?
2 ответа
Чтобы макетировать тип, он должен быть либо интерфейсом (это также называется чисто виртуальным), либо иметь виртуальных членов (абстрактные члены также являются виртуальными).
По этому определению вы можете издеваться над всем, что является виртуальным.
По сути, динамические макеты не делают ничего, что вы не могли бы сделать вручную.
Допустим, вы программируете с помощью интерфейса, такого как этот:
public interface IMyInterface
{
string Foo(string s);
}
Вы можете вручную создать тестовую реализацию IMyInterface, которая игнорирует входной параметр и всегда возвращает один и тот же результат:
public class MyClass : IMyInterface
{
public string Foo(string s)
{
return "Bar";
}
}
Тем не менее, это очень быстро повторяется, если вы хотите проверить, как потребитель реагирует на различные возвращаемые значения, так что вместо того, чтобы вручную кодировать ваши тестовые двойники, вы можете создать среду, динамически создающую их для вас.
Представьте, что динамические mocks действительно пишут код, похожий на реализацию 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";
}
}
Динамическая фиктивная библиотека может делать то же самое, и то же самое верно для абстрактных методов.
Тем не менее, вы не можете написать код, который переопределяет не виртуальный или внутренний элемент, и ни один не может динамически имитировать. Они могут делать только то, что вы можете делать вручную.
Предостережение: приведенное выше описание верно для большинства динамических макетов, за исключением TypeMock, который отличается и... страшен.
Вы можете использовать Moq для создания макетов как из интерфейсов, так и из существующих классов. Есть некоторые требования к занятиям. Класс не может быть запечатан. Кроме того, метод, который надо смоделировать, должен быть помечен как виртуальный. Вы не можете смоделировать статические методы (используйте шаблон адаптера для насмешки статического метода).