Подтвердить что ты не робот

Как мне издеваться над классом без интерфейса?

Я работаю на .NET 4.0 с использованием С# в Windows 7.

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

Я только что прочитал много тем и несколько уроков о фиктивных объектах, но все они использовались для имитации интерфейсов, а не классов. Я пытался использовать рамки Rhino и Moq.

4b9b3361

Ответ 1

Просто отметьте любой метод, который нужно подделать как virtual (а не частный). Затем вы сможете создать фальшивку, которая может переопределить метод.

Если вы используете new Mock<Type>, и у вас нет конструктора без параметров, вы можете передать параметры в качестве аргументов вышеуказанного вызова, так как он принимает тип param Objects

Ответ 2

Большинство издевательских фреймворков (включая Moq и RhinoMocks) генерируют прокси-классы в качестве замены вашего издевающегося класса и переопределяют виртуальные методы с поведением, которое вы определяете. Из-за этого вы можете только имитировать интерфейсы или виртуальные методы на конкретных или абстрактных классах. Кроме того, если вы издеваетесь над конкретным классом, вам почти всегда нужно предоставить конструктор без параметров, чтобы насмешливая структура знала, как создать экземпляр класса.

Почему отвращение к созданию интерфейсов в вашем коде?

Ответ 3

С помощью MoQ вы можете издеваться над конкретными классами:

var mocked = new Mock<MyConcreteClass>();

но это позволяет вам переопределить код virtual (методы и свойства).

Ответ 4

Стандартные насмешливые фреймворки создают прокси-классы. Именно по этой причине они технически ограничены интерфейсами и виртуальными методами.

Если вы хотите издеваться над "нормальными" методами, вам нужен инструмент, который работает с инструментами вместо генерации прокси. Например. MS Moles и Typemock могут это сделать. Но у первого есть ужасный "API", а последний - коммерческий.

Ответ 5

Я думаю, что лучше создать интерфейс для этого класса. И создать unit тест, используя интерфейс.

Если у вас нет доступа к этому классу, вы можете создать адаптер для этого класса.

Например:

public class RealClass
{
    int DoSomething(string input)
    {
        // real implementation here
    }
}

public interface IRealClassAdapter
{
    int DoSomething(string input);
}

public class RealClassAdapter : IRealClassAdapter
{
    readonly RealClass _realClass;

    public RealClassAdapter() => _realClass = new RealClass();

    int DoSomething(string input) => _realClass.DoSomething(input);
}

Таким образом, вы можете легко создать макет для вашего класса, используя IRealClassAdapter.

Надеюсь, что это работает.

Ответ 6

Если вы не можете изменить тестируемый класс, то единственным вариантом, который я могу предложить, является использование MS Fakes https://msdn.microsoft.com/en-us/library/hh549175.aspx. Тем не менее, MS Fakes работает только в нескольких редакциях Visual Studio.

Ответ 7

Если хуже ухудшается, вы можете создать пару интерфейсов и адаптеров. Вы изменили бы все использование ConcreteClass вместо использования интерфейса и всегда передавали адаптер вместо конкретного класса в производственный код.

Адаптер реализует интерфейс, поэтому макет может также реализовать интерфейс.

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

Ответ 8

Я столкнулся с чем-то подобным в одном из старых и унаследованных проектов, в которых я работал, который не содержит никаких интерфейсов или передового опыта, а также слишком сложно заставить их создавать вещи заново или реорганизовывать код из-за зрелости проектного бизнеса, поэтому в моем проекте UnitTest я использовал для создания Wrapper над классами, которые я хочу смоделировать, и реализует интерфейс оболочки, который содержит все мои необходимые методы, с которыми я хочу установить и работать. Теперь я могу смоделировать оболочку вместо реального класса.

Например:

Сервис, который вы хотите протестировать, который не содержит виртуальных методов или интерфейса реализации

public class ServiceA{

public void A(){}

public String B(){}

}

Оболочка в МОК

public class ServiceAWrapper : IServiceAWrapper{

public void A(){}

public String B(){}

}

Интерфейс Обертки

public interface IServiceAWrapper{

void A();

String B();

}

В модульном тесте теперь можно смоделировать обертку:

    public void A_Run_ChangeStateOfX()
    {
    var moq = new Mock<IServiceAWrapper>();
    moq.Setup(...);
    }

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

Обновление: ответ более года, но в этом году я столкнулся с множеством похожих сценариев с различными решениями. Например, с помощью Microsoft Fake Framework легко создавать макеты, подделки и заглушки и даже тестировать закрытые и защищенные методы без каких-либо интерфейсов. Вы можете прочитать: https://docs.microsoft.com/en-us/visualstudio/test/isolating-code-under-test-with-microsoft-fakes?view=vs-2017