首页 > 解决方案 > 使用 Laravel assertDatabaseHas 和浮点列进行单元测试

问题描述

在我的 Laravel 应用程序上进行一些测试,由于我的数据库列之一被定义为FLOAT. 使用assertDatabaseHas()它运行测试时,有时会由于浮点不确定性而失败。

<?php

namespace Test\Unit;

use App\Foo;

class MyModelTest extends TestCase
{
    public function testFooCanBar(): void
    {
        $stringvalue = "baz";
        $floatvalue = 234.281;
        $data = [
            "name" => $stringvalue,
            "data" => $floatvalue,
        ];
        Foo::bar($stringvalue, $floatvalue);
        $this->assertDatabaseHas("foos", $data);
    }
}

有时结果:

Failed asserting that a row in the table [foos] matches the attributes {
    "name": "baz",
    "data": 234.281
}.

Found similar results: [
    {
        "name": "baz",
        "data": 234.280999999999999995
    }
]

我可以想出几种方法来解决这个问题(将列更改为 anINT并乘以 10^x,或者只是从比较中删除列)但我想知道是否有任何方法我错过了正确检查这个。当直接比较值时,我们可以使用 PHPUnit 的assertEqualsWithDelta(); 数据库检查有什么类似的吗?

标签: phplaravelunit-testingfloating-pointphpunit

解决方案


在 MySQL 数据库(当前为 v8)中,aFLOATDOUBLE数据类型始终存储为近似值:

FLOAT 和 DOUBLE 类型表示近似数值数据值。MySQL 对单精度值使用四个字节,对双精度值使用八个字节。

— 来自:MySQL FLOAT 和 DOUBLE 数据类型参考

另一方面,DECIMAL数据类型允许您存储长达 65 位的精确十进制值。

DECIMAL 和 NUMERIC 类型存储精确的数字数据值。当保持精确的精度很重要时使用这些类型,例如货币数据。

— 来自:MySQL DECIMAL 数据类型参考

FLOAT 的问题(参考)

MySQL 文档涵盖了数据类型不准确的问题,并显示了在数据库级别使用这些类型和差异差异的可能解决方案(参考链接中的完整示例)FLOATDOUBLE

SELECT i, SUM(d1) AS a, SUM(d2) AS b
FROM t1
GROUP BY i
HAVING ABS(a - b) > 0.0001;

重要提示:请记住,这FLOAT也是DOUBLE平台相关的!

SELECT像下面这样的语句可以根据运行时环境返回0and-0infand :-inf

CREATE TABLE t1(c1 FLOAT(53,0), c2 FLOAT(53,0));
INSERT INTO t1 VALUES('1e+52','-1e+52');
SELECT * FROM t1;

推荐阅读