Результаты метода имитации

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

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

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

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

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

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

Пожалуйста, посмотрите: stackoverflow.com/questions/90851/…

Marcio Aguiar 18.09.2008 12:28
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
9
1
4 790
6
Перейти к ответу Данный вопрос помечен как решенный

Ответы 6

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

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

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

AFAIK, если Helper - это просто обычный класс, вы не можете издеваться над его методами.

Dario Solera 18.09.2008 11:16
Ответ принят как подходящий

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

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

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

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

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

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

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

Что касается вашего предупреждения ... На самом деле это называется инверсией управления. Это не плохо, если вы все сделаете правильно. :)

Justin Bozonier 19.09.2008 04:19

Да, я знаю этот термин. Да, ОЧЕНЬ ХОРОШО, когда все сделано правильно. Здесь не тот случай.

Marcio Aguiar 19.09.2008 11:11

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

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

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

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

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, и передаете его конструктору, и ваш класс будет использовать его, как если бы это был настоящий класс Helper.

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

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

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

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

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