Как мне смоделировать метод с параметром открытого массива в PascalMock? - PullRequest
2 голосов
/ 20 мая 2010

Я сейчас нахожусь в процессе начала модульного тестирования и насмешек, и я наткнулся на следующий метод, который, как мне кажется, не может сфабриковать рабочую макетную реализацию для:

function GetInstance(const AIID: TGUID; 
                       out AInstance; 
                     const AArgs: array of const; 
                     const AContextID: TImplContextID = CID_DEFAULT): Boolean;

(TImplContextID это просто псевдоним типа для Integer)

Вот как далеко я дошел:

function TImplementationProviderMock.GetInstance(
  const AIID: TGUID;
    out AInstance;
  const AArgs: array of const;
  const AContextID: TImplContextID): Boolean;
var
  lCall: TMockMethod;
begin
  lCall := AddCall('GetInstance').WithParams([@AIID, AContextID]);
  Pointer(AInstance) := FindVarData(lCall.OutParams[0]).VPointer;
  Result := lCall.ReturnValue;
end;

Но я не смог выяснить, как я должен издеваться над параметром открытого массива AArgs. Есть идеи?

Кроме того, возможно, существует более простой способ вернуть out -параметр AInstance и использовать нотацию @ для параметра TGUID (по существу, запись, т.е. тип значения) правильный путь?

Можно ли вообще смоделировать этот метод с текущей версией PascalMock?


Обновление 2: Теперь я сократил текст вопроса для ясности. Первоначально он содержал следующую ошибочную реализацию метода макета, на которую ссылается ответ Мейсона:

function TImplementationProviderMock.GetInstance(
  const AIID: TGUID;
    out AInstance;
  const AArgs: array of const;
  const AContextID: TImplContextID): Boolean;
begin
  Result := AddCall('GetInstance')
           .WithParams([@AIID, AContextID])
           .ReturnsOutParams([AInstance])
           .ReturnValue;
end;

В этом случае компилятор пожаловался на .ReturnsOutParams([AInstance]), говорящее «Неверный тип аргумента в конструкторе массива типа переменной».

Ответы [ 2 ]

0 голосов
/ 11 июня 2010

Я сейчас придумал несколько сложное решение, которое не совсем идеально с точки зрения OO- POV, потому что это требует, чтобы разработчик теста знал, как макет реализован внутри, но я думаю, что это все еще несколько приемлемо, так как нельзя делать никаких предположений о том, как еще указать ожидание аргумента в открытом массиве (по крайней мере, ни одно из них не скомпилирует) .

Итак, вот как выглядит реализация моего смоделированного метода:

function TImplementationProviderMock.GetInstance(
  const AIID: TGUID;
    out AInstance;
  const AArgs: array of const;
  const AContextID: TImplContextID): Boolean;
var
  lCall: TMockMethod;
  lArgs: TOpenArray;
begin
  lArgs := ConcatArrays([ArgsToArray([@AIID]), ArgsToArray(AArgs), ArgsToArray([AContextID])]);
  lCall := AddCall('GetInstance').WithParams(lArgs);
  Pointer(AInstance) := FindVarData(lCall.OutParams[0]).VPointer;
  Result := lCall.ReturnValue;
end;

Как вы видите, суть моего решения состояла в том, чтобы создать мой собственный array of TVarRec (он же TOpenArray), который я мог бы затем передать методу WithParams. Я написал несколько служебных программ, которые позволили мне объединить явные аргументы с аргументами открытого массива в один новый массив.

Вот реализация ConcatArrays:

type TOpenArray = array of TVarRec;

function ConcatArrays(const AArrays: array of TOpenArray): TOpenArray;
var
  lLength: Integer;
  lArray: TOpenArray;
  lIdx: Integer;
  lElem: TVarRec;
begin
  lLength := 0;
  for lArray in AArrays do
    Inc(lLength, Length(lArray));
  SetLength(Result, lLength);
  lIdx := -1;
  for lArray in AArrays do
    for lElem in lArray do
      begin
        Inc(lIdx);
        Result[lIdx] := lElem;
      end;
end;

У меня есть сильное подозрение, что эти подпрограммы, вероятно, могут быть массово оптимизированы кем-то, кто лучше понимает, как Delphi обрабатывает динамические и открытые массивы внутри.

В любом случае, с этим решением на месте тестирования, я теперь должен игнорировать тот факт, что в методе mocked есть даже параметр открытого массива. Я просто указываю ожидание как таковое:

FMock.Expects('GetInstance').WithParams([@IMyIntf, 1, 2, 3, lContextID]).ReturnsOutParam(lDummy).Returns(True);

... где 1, 2, 3 -бит действительно является ожидаемым аргументом открытого массива.

0 голосов
/ 20 мая 2010

Похоже, ReturnsOutParams ожидает массив const , который реализован внутри как массив TVarRec. TVarRec - это запись, которая похожа на вариант, но отличается, и требует, чтобы компилятор заполнил ее определенным типом. Нетипизированный параметр не войдет в него.

Подобные вещи, вероятно, могут быть сделаны с расширенным RTTI Delphi 2010, но не с TVarRec.

...