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

Могу ли я получить NSubstitute для автоматического издевательства над моими конкретными классами?

У меня есть интерфейс, который я издеваюсь над "NSubstitute" , который содержит свойства, возвращающие классы concreate, то есть возвращаемое значение не является интерфейсом. например

public interface ISomething
{
    SomeObj First { get; }
    SomeObj Second { get; }
}

В конкретном классе "SomeObj" есть конструктор по умолчанию, но "NSubstitute" всегда возвращает "null" для этих свойств. Сам класс не находится под моим контролем, поэтому я не могу просто сделать его результатом интерфейса.

Может ли "NSubstitute" издеваться над этими типами свойств? Или есть способ переопределить поведение? В противном случае мне придется вручную инициализировать макет перед тестом, и это может быть много кода (даже если его использовать повторно с помощью обычного метода).

Возможно, есть более простое решение, которое я просмотрел?

4b9b3361

Ответ 1

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

NSubstitute не имеет способа переопределить это поведение. Вместо этого я бы рекомендовал создать все ваши заменители с помощью собственного метода factory (например, статического метода Sub.For<T>(...) в вашем тестовом проекте), который использует NSubstitute для создания замены, а затем применяет все необходимые правила инициализации, которые вам нужны, например, используя отражение для исключения значений для каждого свойства класса.

Надеюсь, что это поможет.

Возможно связанные ссылки:

Ответ 2

Это не считается автоматическим насмешкой, но вы также спрашивали: "Или есть способ переопределить поведение?" и "Возможно, есть более простое решение, которое я просмотрел?"

Этот ответ основывается на утверждениях в вашем вопросе о том, что:

  • SomeObj - это класс вне вашего контроля, из которого я предполагаю, что он либо отдельно протестирован, либо не тестируется
  • SomeObj имеет конструктор по умолчанию

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

public class SomeObj
{
    // Non-virtual to prevent auto-mocking
    public void Dummy() { }
}
public interface ISomething
{
    SomeObj First { get; }
    SomeObj Second { get; }
}
[TestMethod]
public void Test_17182355ms()
{
    ISomething mockedSomething = Substitute.For<ISomething>();

    SomeObj firstObj = mockedSomething.First;
    Assert.IsNull(firstObj);
    mockedSomething.First.Returns(new SomeObj());
    mockedSomething.Second.Returns(new SomeObj());
    firstObj = mockedSomething.First;
    Assert.IsNotNull(firstObj);
}

Другой подход, хотя и не лишенный собственных недостатков, заключается в извлечении собственного интерфейса для SomeObj, примерно так:

public interface ISomeObj
{
    void Dummy();
}
public class MySomeObj : SomeObj, ISomeObj
{
}

а затем введите ISomeObj в свой тест.