Ad

Doubles Losing Their Decimal Places In Unit Tests

- 1 answer

So I am in the process of upgrading an old Laravel project from 5.3 to 5.4 (plan on going to 5.8), but I've run into a problem with my unit tests in which doubles are losing their decimal places.

Here's an example of one such test (yes my tests interact with a database):

$this->user->message_score = 3.42;
$this->user->save();
echo $this->user->fresh()->message_score; // 3

The migration for the table:

$table->double('message_score')->nullable();

Whatever number I set, the decimal places are lost. It isn't round up or down, 3.42 becomes 3, as does 3.99.

Tinker does not have the same issue.

I assume I am missing something simple.

Any help is appreciated.

EDIT

So I ran a migration to update the message_score precision and I am running into the same problem. The length displayed in the database before running the migration was (8,2) and the migration I ran pushed it up to (10,8). The migration is below:

DB::statement('ALTER TABLE `users` MODIFY `message_score` DOUBLE(10,8) NOT NULL DEFAULT 0.0;');
Ad

Answer

The problem is related to the MYSQL connection, specifically setting PDO::ATTR_EMULATE_PREPARES to true.

PDO::ATTR_EMULATE_PREPARES is what allows you to reuse parameters in a prepared statement, for example, you could just use :id instead of :id1, :id2, :id3. When it is set to true on PHP >= 7.2, it causes all floats to be cast to an integer, therefore losing the precision. This is due to Laravel not supporting this PDO flag.

There are essentially two options:

Set PDO::ATTR_EMULATE_PREPARES to false and then start uniquely naming parameters, like so :id1, :id2, :id3.

Or

Set your floats to strings, at which point they will keep their decimals place as Laravel will no longer see it as a float and cast it to an integer.

Here is the issue on GitHub if you want to read more into it: https://github.com/laravel/framework/issues/23850

Ad
source: stackoverflow.com
Ad