将 spring.Nullable 与 DUnitX 一起使用时出现内存问题
Memory issues when using spring.Nullable with DUnitX
最近在我的公司,我们尝试使用 DUnitX 来测试我们编写的 类。由于那些 类 反映了数据库中的实体,所有字段都必须接受空值以及特定类型(例如整数或字符串)。
因为 spring4d 已经有了我们尝试使用的那些:
INaleznosc = interface
['{D5D6C901-3DB9-4EC2-8070-EB0BEDBC7B06}']
function DajPodstawaVAT(): TNullableCurrency;
property PodstawaVAT: TNullableCurrency read DajPodstawaVAT;
end;
TNaleznosc = class(TInterfacedObject, INaleznosc)
strict private
FId: TNullableInt64;
FPodstawaVAT: Currency;
function TNaleznosc.DajPodstawaVAT(): TNullableCurrency;
published
property PodstawaVAT: TNullableCurrency read DajPodstawaVAT;
end;
INaleznoscFunkcje = interface
['{509288AB-110A-4A52-BE93-3723E5725F4B}']
function DajPodstawaVAT(pID: TNullableInt64): TNullableCurrency;
end;
function TNaleznosc.DajPodstawaVAT(): TNullableCurrency;
begin
FPodstawaVAT := FFunkcje.DajPodstawaVAT(FId);
end;
procedure TTestNaleznosc.PodstawaVATGetterNieWywolujefunkcji();
var
funkcjeNaleznosc: TMock<INaleznoscFunkcje>;
klasa: INaleznosc;
id: TNullableInteger;
begin
//initialize tested elements
funkcjeNaleznosc := TMock<INaleznoscFunkcje>.Create();
id := 15;
klasa := TNaleznosc.Create(funkcjeNaleznosc, id, zmienne);
//setup expected behaviour from mock
funkcjeNaleznosc.Setup.WillReturn(2).When.DajPodstawaVAT(id);
funkcjeNaleznosc.Setup.Expect.Once.When.DajPodstawaVAT(id);
//this triggers getter
klasa.PodstawaVAT;
end;
执行此代码时,我们得到 AV 异常 First chance exception at [=12=]000000. Exception class $C0000005 with message 'access violation at 0x00000000: access of address 0x00000000'. Process Tests.exe (6556)
。
最终我们将这个问题缩小到 System.Rtti
单元中的移动过程,TValueDataImpl.ExtractRawDataNoCopy
函数:
当 Length(FData) 小于或等于 8 时它工作正常
当 Length(FData) 在 System
单元 (FISTP QWORD PTR [EDX+8] {Save Second 8}
) 的第 5905 行处介于 9 和 32 之间时,整个调用堆栈消失在两行旁边(我们不确定它是否相关,但它不看起来像个好兆头)并且在到达最顶层函数后(根据调用堆栈)我们得到错误。
Call stack before "saving second 8"
Call stack after "saving second 8"
这是我们的错还是 system/spring/dunitx 单位有问题?我们如何同时使用可空类型和测试?
我不确定 Delphi Mocks 是否在其 WillReturn
方法上有泛型类型参数,但如果有,则将 TNullableCurrency
传递到那里 - 否则编译器将从您传递的参数 2
显然在内部它无法将其放入 TNullableCurrency
应该 return.
如果它不允许并且只允许 TValue
那么你需要传递一个包含 TNullableCurrency
而不是 2
的,它将通过使用它的隐式运算符像这样:TValue.From<TNullableCurrency>(2)
此外,我不确定他们是否确实修复了 Delphi 中 SameValue
例程中的代码 Mocks 当要比较的值是记录时(因为 TNullableCurrency
是)
编辑:不,他们没有 - 参见 https://github.com/VSoftTechnologies/Delphi-Mocks/issues/39
您可能想考虑尝试一下 Spring4D 模拟,它应该能够处理可空值。
最近在我的公司,我们尝试使用 DUnitX 来测试我们编写的 类。由于那些 类 反映了数据库中的实体,所有字段都必须接受空值以及特定类型(例如整数或字符串)。
因为 spring4d 已经有了我们尝试使用的那些:
INaleznosc = interface
['{D5D6C901-3DB9-4EC2-8070-EB0BEDBC7B06}']
function DajPodstawaVAT(): TNullableCurrency;
property PodstawaVAT: TNullableCurrency read DajPodstawaVAT;
end;
TNaleznosc = class(TInterfacedObject, INaleznosc)
strict private
FId: TNullableInt64;
FPodstawaVAT: Currency;
function TNaleznosc.DajPodstawaVAT(): TNullableCurrency;
published
property PodstawaVAT: TNullableCurrency read DajPodstawaVAT;
end;
INaleznoscFunkcje = interface
['{509288AB-110A-4A52-BE93-3723E5725F4B}']
function DajPodstawaVAT(pID: TNullableInt64): TNullableCurrency;
end;
function TNaleznosc.DajPodstawaVAT(): TNullableCurrency;
begin
FPodstawaVAT := FFunkcje.DajPodstawaVAT(FId);
end;
procedure TTestNaleznosc.PodstawaVATGetterNieWywolujefunkcji();
var
funkcjeNaleznosc: TMock<INaleznoscFunkcje>;
klasa: INaleznosc;
id: TNullableInteger;
begin
//initialize tested elements
funkcjeNaleznosc := TMock<INaleznoscFunkcje>.Create();
id := 15;
klasa := TNaleznosc.Create(funkcjeNaleznosc, id, zmienne);
//setup expected behaviour from mock
funkcjeNaleznosc.Setup.WillReturn(2).When.DajPodstawaVAT(id);
funkcjeNaleznosc.Setup.Expect.Once.When.DajPodstawaVAT(id);
//this triggers getter
klasa.PodstawaVAT;
end;
执行此代码时,我们得到 AV 异常 First chance exception at [=12=]000000. Exception class $C0000005 with message 'access violation at 0x00000000: access of address 0x00000000'. Process Tests.exe (6556)
。
最终我们将这个问题缩小到 System.Rtti
单元中的移动过程,TValueDataImpl.ExtractRawDataNoCopy
函数:
当 Length(FData) 小于或等于 8 时它工作正常
当 Length(FData) 在 System
单元 (FISTP QWORD PTR [EDX+8] {Save Second 8}
) 的第 5905 行处介于 9 和 32 之间时,整个调用堆栈消失在两行旁边(我们不确定它是否相关,但它不看起来像个好兆头)并且在到达最顶层函数后(根据调用堆栈)我们得到错误。
Call stack before "saving second 8"
Call stack after "saving second 8"
这是我们的错还是 system/spring/dunitx 单位有问题?我们如何同时使用可空类型和测试?
我不确定 Delphi Mocks 是否在其 WillReturn
方法上有泛型类型参数,但如果有,则将 TNullableCurrency
传递到那里 - 否则编译器将从您传递的参数 2
显然在内部它无法将其放入 TNullableCurrency
应该 return.
如果它不允许并且只允许 TValue
那么你需要传递一个包含 TNullableCurrency
而不是 2
的,它将通过使用它的隐式运算符像这样:TValue.From<TNullableCurrency>(2)
此外,我不确定他们是否确实修复了 Delphi 中 SameValue
例程中的代码 Mocks 当要比较的值是记录时(因为 TNullableCurrency
是)
编辑:不,他们没有 - 参见 https://github.com/VSoftTechnologies/Delphi-Mocks/issues/39
您可能想考虑尝试一下 Spring4D 模拟,它应该能够处理可空值。