Модульное тестирование: как сломать локальную объектную зависимость? - PullRequest
3 голосов
/ 04 октября 2011

У меня есть такой код:

class B;

class A
{
  A()
  {
  }
  bool MethodA()
  {
    B *pB = new B();
    bool bRet = pB->SomeFunction();
    // remaining logic;
    return bRet;
  }
  ~A(){}
};

Мне нужно написать тесты для MethodA .Поэтому я думаю, что мне нужно сломать зависимость от класса B .Каков наилучший способ сделать это?Если бы это была переменная-член, я мог бы вставить заглушку через конструктор.Есть ли какое-либо решение, которое не предполагает изменения в производственном коде ?Если изменение необходимо, что лучше?

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

edit: Есть еще одна головная боль, которую я пропустил!класс B является классом C ++, и я не должен менять его реализацию.класс A находится в C ++ / CLI, который действует как оболочка для B. Поэтому я думаю, что это снижает вероятность интерфейса для B, поскольку я не могу коснуться B.

Ответы [ 2 ]

2 голосов
/ 04 октября 2011

Нет. Не существует решения, которое не включает в себя изменение этого дизайна, в основном потому, что этот проект плохой . A и его зависимость B тесно связаны между собой, что делает его плохим с точки зрения объектно-ориентированного программирования: вам необходимо инвертировать управление зависимостями. Тестирование - это только одна из причин плохого дизайна, но не единственная. Переносимость, гибкость, разделение интересов, другие.

Лучший способ (единственный хороший способ) сделать его тестируемым и улучшить его - это внедрение зависимостей . Вам нужно ввести B в A, используя либо конструктор (который принимает интерфейс к B в качестве параметра), либо установщик. И тот, кто контролирует A (и делает new A()), должен передать ей зависимость B (new A(new B()) или A.setB(new B())).

Как только это будет сделано, юнит-тестирование метода станет очень простым.

1 голос
/ 04 октября 2011

Вы не можете сделать это без внесения изменений, но вы можете сделать что-то вроде:

class A
{
  A()
  {
  }


  A(B *b)
  {
     pB = b;
  }

  B *pB;

  bool MethodA()
  {
    if (*pB == null) {
      *pB = new B();
    }
    bool bRet = pB->SomeFunction();
    // remaining logic;
    return bRet;
  }
  ~A(){}
};

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

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