【发布时间】:2017-09-26 18:25:50
【问题描述】:
我编写了一个接口来包装 Windows 线程池 API,其中许多函数返回普通的 Pointer 类型。
现在我正在编写测试并想使用 delphi-mocks framework 来模拟该包装器接口。
问题在于TMock 设置接口采用TValue 对象来指定模拟函数的默认返回值,而我无法从可用的TValue 函数中看到如何正确执行此操作的方法。虽然我已经看到 ekPointer 是一个有效的 TTypeKind 值。
当调用模拟函数时,我从相应的 RTTI 调用中收到 EInvalidCast 异常。
当 RTTI 调用尝试从隐式 TValue 对象转换返回类型值时,就会发生这种情况。
我的代码大致是这样的1:
type
PTP_POOL = Pointer;
PTP_CLEANUP_GROUP = Pointer;
IThreadPoolApi = interface(IInterface)
{...}
function CreateThreadPool() : PTP_POOL;
function CreateThreadpoolCleanupGroup() : PTP_CLEANUP_GROUP;
{...}
end;
被测类
type
TThreadPool = class(TInterfacedObject, IThreadPool)
FTPApi : IThreadPoolApi;
FPTPPool : PTP_POOL;
FPTPCleanupGroup : PTP_CLEANUP_GROUP;
{...}
public
constructor Create(iapi : IThreadPoolApi);
end;
implementation
constructor TThreadPool.Create(iapi : IThreadPoolApi);
begin
inherited Create();
FTPApi := iapi;
{**** Here I get a EInvalidCast exception when mocking the interface ****}
FPTPPool := FTPApi.CreateThreadPool();
if(not assigned(FPTPPool)) then
begin
{Raise exception}
raise EThreadPoolError('Cannot create TP thread pool');
end;
{**** This case should be tested ****}
FPTPCleanupGroup := FTPApi.CreateThreadpoolCleanupGroup();
if(not assigned(FPTPPool)) then
begin
{Raise exception}
raise EThreadPoolError('Cannot create TP cleanup group');
end;
{...}
end;
和测试的东西
procedure ThreadPoolTest.TestFail_CreateThreadpoolCleanupGroup();
var
apiMock : TMock<IThreadPoolApi>;
testproc : TTestLocalMethod;
begin
apiMock := TMock<IThreadPoolApi>Create();
{**** Needed to reach the call of CreateThreadpoolCleanupGroup
but EInvalidCast is raised ****}
apiMock.Setup.WillReturnDefault('CreateThreadPool',PTP_POOL($FFFFFFFF));
{**** The case to be tested ****}
apiMock.Setup.WillExecute('CreateThreadpoolCleanupGroup',
function (const args : TArray<TValue>; const ReturnType : TRttiType)
: TValue
begin
result := nil;
end);
testproc :=
procedure()
var
threadpool : IThreadPool;
begin
threadpool := TThreadPool.Create(apiMock);
end;
DUnitX.Assert.WillRaise(testproc,EThreadPoolError,
'Cannot create TP cleanup group');
end;
TL;DR;
所以问题是:
我需要做什么才能正确创建 TValue 以包含 PTP_POOL 指针类型?
1)设置MCVE的代码有点多,所以我在这里画了个草图给你背景,看{**** highlighted comments ****}
【问题讨论】:
-
关于 DV。为这个问题设置 MCVE 有点困难,但无论如何这都不是问题。请跳到 TL;DR;。我很清楚发生了什么。
-
我不明白你到底在问什么。而且您没有显示导致问题的
CreateThreadPool()的实现。另一方面,您的WillExecute()过程中的result := nil;可能应该是Result := TValue.From<Pointer>(nil);。TValue没有原始指针的隐式转换,但它确实有TObject指针的隐式转换。 -
@RemyLebeau “我不明白你到底在问什么。” 我相信这很清楚。只需阅读问题末尾的问题即可。
WillExecute() procedure效果很好(我做到了,因为使用WillReturnDefault()和nil效果不佳)。但是您使用TValue.From<PTP_POOL>($FFFFFFFF);使用WillReturnDefault()创建TValue的评论可能回答了我的问题。我明天回到我的办公桌前测试一下。 -
您必须改用
TValue.From<PTP_POOL>(PTP_POOL($FFFFFFFF))。除非你对它进行类型转换,否则你不能在需要指针的地方传递十六进制文字,否则你会得到一个错误:E2010 Incompatible types: 'Pointer' and 'Integer'
标签: delphi delphi-xe2 rtti delphi-mocks