我编写了一个包装Windows Threadpool API的接口,其中许多函数返回普通的Pointer
类型。
现在,我正在编写测试,并想使用delphi-mocks framework模拟该包装器接口。
问题在于TMock
设置界面使用TValue
对象为模拟函数指定默认返回值,而我无法从可用的TValue
函数中看到如何正确执行此操作的方法。尽管我已经看到ekPointer
是有效的TTypeKind
值。
调用模拟函数时,我从相应的RTTI调用接收到EInvalidCast
异常。
当RTTI调用尝试从隐式TValue
对象转换返回类型值时,就会发生这种情况。
我的代码大致如下所示:
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 ****}
最佳答案
将原始指针分配给TValue
时,请使用TValue.From<T>()
方法,例如:
TValue.From<PTP_POOL>(nil);
或者,如果要返回文字值:
TValue.From<PTP_POOL>(PTP_POOL(value));
TValue
没有针对原始指针的隐式转换,但确实具有针对TObject
和TClass
指针的隐式转换。如果直接将无类型的nil指针分配给
TValue
,它将调用TValue.Implicit(TObject)
,当传递nil指针时,它将返回TValue.Empty
属性。如果将类型化的非
TObject
指针直接分配给TValue
,它将调用TValue.Implicit(TClass)
,如果指针为nil,则返回TValue.Empty
,否则返回值为TValue
的TClass
类型指针,即使它实际上没有指向有效的类类型也是如此。如果将指针传递给
TValue.From<T>()
,即使它为nil,它也会返回带有指针值的TValue
类型的T
。这种差异是微妙的,但非常重要。
关于delphi - EInvalidCast带模拟函数返回指针类型,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/46433385/