Как мне издеваться над классом, который не имеет виртуальных методов? - PullRequest
7 голосов
/ 03 мая 2011

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

Теперь давайте предположим, что вам нужно смоделировать класс, определенный как:

TMyClass = class
public
  procedure Method1;
  procedure Method2
end;  

Method1 и Method2 не являются виртуальными. Что вы делаете в этом случае? Чтобы смоделировать объект, нам нужно унаследовать его и override каждый метод, который вы хотите смоделировать, но в этом случае это невозможно, потому что они не virtual. Должен ли я изменить исходный код, добавив virtual к каждому методу, который мне нужен? Разве это не плохо?

Редактировать

Я думал о создании директивы компилятора, чтобы все поля в классе были virtual, это хорошая идея? Только мой набор тестов будет устанавливать директиву компилятора.

EDIT2 *

Embarcadero должен обеспечивать простой способ изменения указателя метода класса на другую точку метода без необходимости virtual.

Ответы [ 3 ]

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

Сделайте методы виртуальными , чтобы вы могли их высмеивать. (Они не должны быть абстрактными.)

Если вы не можете этого сделать, то оберните класс другим классом. Сделайте методы обертки виртуальными, и в реализации по умолчанию просто перенаправьте вызовы в исходный класс. Везде, где ваша программа использует оригинальный класс, замените его оболочкой. А теперь смейся над обёрткой.

6 голосов
/ 03 мая 2011

Чтобы смоделировать объект, нам нужно наследовать это, но это невозможно в этом случай.

Я бы порекомендовал, чтобы каждый класс, который вы говорите: «Мне нужно высмеивать это», в конечном итоге основывался на интерфейсе.

Другими словами, если у вас есть методы, которые нужно смоделировать, они должны быть помещены в интерфейс, а затем класс, который нужно смоделировать, реализует этот интерфейс. Затем вы создаете макет путем реализации того же интерфейса в объекте макета.

Альтернативой является использование библиотеки Mocking. Вы можете посмотреть на эти вопросы так:

Какая ваша любимая библиотека для насмешек Delphi?

, и этот фреймворк также включает насмешливые объекты:

http://code.google.com/p/emballo/

Пересмешивающие объекты также должны стимулировать правильное использование внедрения кода в ваш код.

5 голосов
/ 03 мая 2011

Вы должны не только делать методы виртуальными, вы должны объявлять чистый виртуальный базовый класс, а другие классы должны использовать только чистое имя виртуального базового класса.Теперь вы можете использовать то, что мы называем «принципом подстановки Лискова», и вы можете создать столько конкретных подтипов абстрактного базового класса, сколько вам нужно.Поскольку абстрактный базовый класс работает так же, как интерфейс работает в Delphi, за исключением части подсчета ссылок, вы получаете лучшее из обоих миров.Вы действительно можете сохранить код своего приложения простым и таким образом уменьшить количество плохих связей, плюс вы получите проверяемые модулем «составные объекты», которые вы собираете сами.

// in UnitBase.pas
TMyClassBase = class
public
  procedure Method1; virtual; abstract;
  procedure Method2; virtual; abstract;
end; 

// in UnitReal.pas
TMyClassReal = class(TMyClassbase)
public
  procedure Method1; override;
  procedure Method2; override;
end; 

// in UnitMock.pas 
TMyClassMock = class(TMyClassbase)
public
  procedure Method1; override;
  procedure Method2; override;
end; 

В месте, где используется «TMyClass», изменитеиспользовать TMyClassbase:

TMyOtherClass = class(TMyOtherClassBase)
private
  FMyThing:TMyClassbase;
public
  property MyThing:TMyClassBase read FMyThing write FMyThing;
end;

Подключив TMyOtherclass во время выполнения, вы можете решить, использовать ли действительный или фиктивный класс:

// in my realapp.pas
MyOtherClassObj :=   TMyotherClass.Create;
MyOtherClassObj.MyThing :=  TMyOtherClassReal.Create;  // real object

// in my unittest.pas
MyOtherClassObj :=   TMyotherClass.Create;
MyOtherClassObj.MyThing :=  TMyOtherClassMock.Create;  // mock object

(не забудьте найти способбесплатно MyOtherClassObj.MyThing позже, или у вас будет утечка)

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