将DUnit CheckEquals中的问题与货币字段值进行比较

时间:2009-01-28 18:27:53

标签: delphi dunit

我正在比较DUnit中的一些货币值,但它在我的机器上根本不起作用(在其他机器上工作,但在我的机器上不工作)。

一个例子:

CheckEquals(16.65, SomeCurrencyFieldValue);

引发:

expected: <16,65> but was: <16,65>

如果进行以下比较,则可以起作用:

var
  Temp: Currency;
begin
  Temp := 16.65;
  CheckEquals(Temp, SomeCurrencyFieldValue);

问题是:当我将值直接传递给CheckEquals方法时,为什么比较不起作用?

4 个答案:

答案 0 :(得分:5)

该问题与Currency值在运行时如何转换为Extended值以及浮点文字在编译时如何转换为Extended值有关。如果在两种情况下转换都不相同,那么传递给CheckEquals的值可能无法相等。

值得在调试器的CPU窗口中检查在准备函数调用时,其中任何一个值是否在到Double的路上经过中间Extended值。额外的转换会影响结果的确切值。

要考虑的另一件事是16.65不能完全表示为Extended值,但 可以完全表示为Currency值。虽然Currency被归类为浮点类型,但它实际上是一个定点缩放的64位整数。这可能是请求在DUnit中额外CheckEquals重载的理由,并将其考虑在内。

答案 1 :(得分:1)

我发现在Delphi 2007 dUnit源代码中只有CheckEquals()用于扩展值。但你可以用这个:

procedure CheckEquals(expected, actual: extended; delta: extended;
  msg: string = ''); overload; virtual;

并为货币值提供适当的增量。

答案 2 :(得分:1)

我遇到了同样的问题。看起来有些DLL会修改FPU(处理器)控制字。这解释了为什么不总是发生错误。当添加一些使用除先前测试套件之外的其他单元的新测试时,它可能突然出现。或者,如果软件更新安装了错误的DLL。我在我的博客上写过:

我还发现Delphi包含一个SafeLoadLibrary函数,用于恢复控制字。

这也解释了为什么原始问题提到问题与机器有关。

答案 3 :(得分:-1)

这是一个建议的解决方案:

procedure CheckEquals(expected, actual: double; Precision:integer; msg:string ='');overload;virtual;

...

procedure TAbstractTest.CheckEquals(expected, actual: double;
  Precision: integer; msg: string);
var
  I: Integer;
begin
  FCheckCalled := true;
  for I := 0 to Precision do begin
    Expected := Expected * 10;
    Actual := Actual * 10;
  end;
  if Round(Expected) <> Round(Actual) then
    FailNotEquals( IntToStr(Round(Expected)), IntToStr(Round(Actual)), msg, CallerAddr);
end;

我知道它的实现不好,但只是一个想法,我更喜欢“delta”,更容易使用。

在当前版本的dunit中,您可以使用

procedure CheckEquals(expected, actual: extended; delta: extended; msg: string = ''); overload; virtual;
CheckEquals(0.011,0.01,0.009,'will pass');