Вопрос

Я пытаюсь найти способ подделать результат метода, вызванного из другого метода.

У меня есть метод "loadData", который вызывает отдельный помощник для получения некоторых данных, а затем преобразует их (я заинтересован в тестировании преобразованного результата).

Итак, у меня есть такой код:

public class MyClass(){
  public void LoadData(){
    SomeProperty = Helper.GetSomeData();
 }
 public object SomeProperty {get;set;}
}

Я хочу получить известный результат от Помощника.Метод GetSomeData().Могу ли я использовать mocking framework (у меня довольно ограниченный опыт работы с Rhino Mocks, но я открыт для всего), чтобы добиться ожидаемого результата?Если да, то каким образом?

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

Это было полезно?

Решение

Насколько я знаю, вы должны создать интерфейс или базовый абстрактный класс для Вспомогательного объекта.С помощью Rhino Mocks вы можете затем вернуть нужное значение.

В качестве альтернативы вы можете добавить перегрузку для loadData, которая принимает в качестве параметров данные, которые вы обычно извлекаете из вспомогательного объекта.Это могло бы быть даже проще.

Другие советы

У вас там какая-то проблема.Я не знаю, является ли это упрощенным сценарием вашего кода, но если Вспомогательный класс используется таким образом, то ваш код не поддается тестированию.Во-первых, Вспомогательный класс используется напрямую, так что вы не могу заменить его макетом.Во-вторых, вы вызываете статический метод.Я не знаю насчет C #, но в Java вы не удается переопределить статические методы.

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

В этой упрощенной версии вашего кода трудно дать вам прямой ответ.У вас есть несколько вариантов:

  • Создайте интерфейс для вспомогательного класса и предоставьте клиенту возможность внедрить вспомогательную реализацию в класс MyClass.Но если Helper на самом деле просто служебный класс, то в этом нет особого смысла.
  • Создайте защищенный метод в MyClass с именем getSomeData и сделайте так, чтобы он вызывал только Helper.LoadSomeData.Затем замените вызов Helper.LoadSomeData в loadData на для getSomeData.Теперь вы можете имитировать метод getSomeData, чтобы вернуть фиктивное значение.

Остерегайтесь простого создания интерфейса для вспомогательного класса и вводите его с помощью метода.Это может привести к раскрытию деталей реализации.Почему клиент должен предоставить реализацию полезность класс для вызова простой операции?Это увеличит сложность клиентов MyClass.

Я бы порекомендовал преобразовать то, что у вас есть, во что-то вроде этого:

public class MyClass()
{
    private IHelper _helper;

    public MyClass()
    {
        //Default constructor normal code would use.
        this._helper = new Helper();
    }

    public MyClass(IHelper helper)
    {
        if(helper == null)
        {
            throw new NullException(); //I forget the exact name but you get my drift ;)
        }
        this._helper = helper;
    }

    public void LoadData()
    {
        SomeProperty = this._helper.GetSomeData();
    }
    public object SomeProperty {get;set;}
}

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

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

Если в какой-то момент вы захотите сделать этот шаг дальше, вы могли бы полностью удалить вспомогательную реализацию по умолчанию из пересмотренного класса и использовать контейнеры IoC (инверсия элемента управления).Однако, если это для вас в новинку, я бы рекомендовал сначала сосредоточиться на основных принципах того, почему все эти дополнительные хлопоты того стоят (это ИМХО).

Ваши модульные тесты будут выглядеть примерно как этот псевдокод:

public Amazing_Mocking_Test()
{
    //Mock object setup
    MockObject mockery = new MockObject();
    IHelper myMock = (IHelper)mockery.createMockObject<IHelper>();
    mockery.On(myMock).Expect("GetSomeData").WithNoArguments().Return(Anything);

    //The actual test
    MyClass testClass = new MyClass(myMock);
    testClass.LoadData();

    //Ensure the mock had all of it's expectations met.
    mockery.VerifyExpectations();
}

Не стесняйтесь комментировать, если у вас есть какие-либо вопросы.(Кстати, я понятия не имею, работает ли весь этот код, я просто ввел его в своем браузере, в основном я иллюстрирую концепции).

Возможно, вы захотите изучить Typemock Isolator, который может "подделывать" вызовы методов, не заставляя вас рефакторинговать ваш код.Я разработчик в этой компании, но решение жизнеспособно, если вы хотите отказаться от изменения своего дизайна (или вынуждены не менять его для удобства тестирования) оно находится на www.Typemock.com

Рой Блог:ISerializable.com

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

Rhino Mocks, Typemock и Moq - все это хорошие варианты для этого.

Сообщение Стивена Уолтера использование Rhino Mocks очень помогло мне, когда я впервые начал играть с Rhino Mocks.

Я бы попробовал что-то вроде этого:

public class MyClass(){
  public void LoadData(IHelper helper){
    SomeProperty = helper.GetSomeData();
 }

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top