Как мне издеваться над приватным полем? - PullRequest
15 голосов
/ 25 февраля 2009

Я действительно новичок в макетах и ​​пытаюсь заменить приватное поле фиктивным объектом. В настоящее время экземпляр частного поля создается в конструкторе. Мой код выглядит как ...

public class Cache {
    private ISnapshot _lastest_snapshot;

    public ISnapshot LatestSnapshot {
        get { return this._lastest_snapshot; }
        private set { this._latest_snapshot = value; }
    }

    public Cache() {
        this.LatestSnapshot = new Snapshot();
    }

    public void Freeze(IUpdates Updates) {
        ISnapshot _next = this.LastestSnapshot.CreateNext();
        _next.FreezeFrom(Updates);
        this.LastestSnapshot = _next;
    }

}

Я пытаюсь создать модульный тест, который утверждает, что ISnapshot.FreezeFrom(IUpdates) вызывается из Cache.Freeze(IUpdates). Я предполагаю, что я должен заменить закрытое поле _latest_snapshot на фиктивный объект (возможно, неверное предположение?). Как бы я поступил так, оставив конструктор без параметров и не делая общедоступным набор LatestSnapshot?

Если я собираюсь написать тест неправильно, пожалуйста, укажите также.

Фактическая реализация ISnapshot.FreezeFrom сама вызывает иерархию других методов с глубоким графом объектов, поэтому я не слишком заинтересован в утверждении графа объектов.

Заранее спасибо.

Ответы [ 9 ]

20 голосов
/ 25 февраля 2009

Я почти цитирую методы из "Эффективная работа с устаревшим кодом" :

  1. Подкласс вашего класса в модульном тесте и замените вашу личную переменную с фиктивным объектом в нем (добавив открытый сеттер или в конструктор). Вы, вероятно, должны сделать переменную защищенной.
  2. Создайте защищенный метод получения для этой закрытой переменной и переопределите его в подклассе тестирования, чтобы вернуть фиктивный объект вместо действительной закрытой переменной.
  3. Создайте защищенный фабричный метод для создания объекта ISnapshot и переопределите его в подклассе тестирования, чтобы он возвращал экземпляр фиктивного объекта вместо реального. Таким образом, конструктор получит правильное значение с самого начала.
  4. Параметризовать конструктор, чтобы получить экземпляр ISnapshot.
4 голосов
/ 25 февраля 2009

Я не думаю, что вам нужно издеваться над закрытыми переменными-членами. Разве вся идея насмешки над тем, что открытый интерфейс объекта работает, как и ожидалось? Закрытые переменные - это детали реализации, которые не касаются макетов.

3 голосов
/ 25 февраля 2009

Я не уверен, что вы можете сделать это. Если вы хотите протестировать _next, то вам, вероятно, придется передать его в качестве параметра, а затем при прохождении модульного теста в объекте Mock, который вы затем сможете протестировать с помощью Expectation. Вот что бы я делал, если бы пытался сделать это в Мок.

В качестве примера того, что я мог бы попробовать использовать инфраструктуру Moq:

Mock<ISnapshot> snapshotMock = new Mock<ISnapshot>();
snapshotMock.Expect(p => p.FreezeFrom(expectedUpdate)).AtMostOnce();
Cache c = new Cache(snapshotMock.Object);
c.Freeze(expectedUpdate);

Примечание: я не пытался скомпилировать приведенный выше код. Просто приведу пример того, как я подхожу к решению этой проблемы.

1 голос
/ 14 декабря 2009

Возможно, будет слишком поздно, чтобы ответить. В любом случае. У меня тоже была похожая проблема.

public class Model
{
  public ISomeClass XYZ{
      get;
      private set;
      }
}

Мне потребовалось установить значение XYZ в моем тестовом примере. Я решил проблему, используя этот синтаксис.

Expect.Call(_model.XYZ).Return(new SomeClass());
_repository.ReplayAll();

В приведенном выше случае мы можем сделать это следующим образом

Expect.Call(_cache.LatestSnapshot).Return(new Snapshot());
_repository.ReplayAll();
1 голос
/ 21 мая 2009

Вопрос, который следует задать: каковы внешне видимые эффекты, если это работает?

Что происходит со всеми этими снимками? Один из вариантов может инициализировать Cache с его первым снимком снаружи, скажем, в конструкторе. Другим может быть насмешка над тем, что вызывает моментальный снимок, который имеет значение вне кэша. Это зависит от того, что вас волнует.

1 голос
/ 25 февраля 2009

Этот ответ может быть простым, но, глядя на код, есть ли способ, которым ISnapshot.FreezeFrom(IUpdates) не будет вызван? Звучит так, будто ты хочешь утверждать что-то, что всегда будет правдой.

Как говорит Джейсон, насмешка предназначена для ситуаций, когда ваш класс зависит от SomeInterface, чтобы выполнить свою работу, и вы хотите протестировать YourClass в отрыве от реализации SomeInterface, которую вы фактически используете во время выполнения.

0 голосов
/ 12 мая 2011

Вы можете просто добавить метод "setSnapshot (ISnapshot)" в Cache с вашим экземпляром проверяемого класса.

Вы также можете добавить конструктор, который принимает ISnapshot.

0 голосов
/ 16 февраля 2011

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

public class Cache {
 private ISnapshot _lastest_snapshot;

 public ISnapshot LatestSnapshot {
  get { return this._lastest_snapshot; }
  private set { this._latest_snapshot = value; }
 }

 public Cache() : this (new Snapshot()) {
 }

 public Cache(ISnapshot latestSnapshot) {
  this.LatestSnapshot = latestSnapshot;
 }

 public void Freeze(IUpdates Updates) {
  ISnapshot _next = this.LastestSnapshot.CreateNext();
  _next.FreezeFrom(Updates);
  this.LastestSnapshot = _next;
 }

}
0 голосов
/ 24 сентября 2010

Превратите Cache в шаблон, как показано ниже.

template <typename T=ISnapshot>
public class Cache {
    private T _lastest_snapshot;

    public T LatestSnapshot {
        get { return this._lastest_snapshot; }
        private set { this._latest_snapshot = value; }
    }

    public Cache() {
        this.LatestSnapshot = new Snapshot();
    }

    public void Freeze(IUpdates Updates) {
        T _next = this.LastestSnapshot.CreateNext();
        _next.FreezeFrom(Updates);
        this.LastestSnapshot = _next;
    }

}

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

Cache<> foo;//OR
Cache<ISnapshot> bar;

В тестовом коде сделать:

Cache<MockSnapshot> mockFoo;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...