Solution: 4

PHPUnit 10.2.2 by Sebastian Bergmann and contributors.

Runtime:       PHP 8.2.14
Configuration: phpunit.xml

......                                                              6 / 6 (100%)

Time: 00:00.002, Memory: 24.41 MB

Measurements
 ✔ Centimeters can be converted to int
 ✔ Centimeters can be converted to meters
 ✔ Centimeters cannot be negative
 ✔ Meters can be converted to float
 ✔ Meters can be converted to centimeters
 ✔ Meters cannot be negative

OK (6 tests, 6 assertions)
Output of phpunit --testdox
Execute phpunit --testdox

The conversion in the other direction works the same way:

#[Test]
public function meters_can_be_converted_to_centimeters(): void
{
    $measure = new Meter(1.53);

    $this->assertEquals(new Centimeter(153), $measure->asCentimeter());
}
MeasurementsTest.php

Once we are satisfied that the test fails, we add the appropriate method to the Meter class:

public function asCentimeter(): Centimeter
{
    return new Centimeter((int) ($this->meters * 100));
}
Meter.php

The solution at a glance:

<?php declare(strict_types=1);

use PHPUnit\Framework\Attributes\CoversClass;
use PHPUnit\Framework\Attributes\Test;
use PHPUnit\Framework\TestCase;

#[CoversClass(Meter::class)]
#[CoversClass(Centimeter::class)]
class MeasurementsTest extends TestCase
{
    #[Test]
    public function centimeters_can_be_converted_to_int(): void
    {
        $centimeters = 23;
        $measure = new Centimeter($centimeters);

        $this->assertEquals($centimeters, $measure->asInt());
    }

    #[Test]
    public function centimeters_can_be_converted_to_meters(): void
    {
        $centimeters = 123;
        $measure = new Centimeter($centimeters);

        $this->assertEquals(new Meter(1.23), $measure->asMeter());
    }

    #[Test]
    public function centimeters_cannot_be_negative(): void
    {
        $this->expectException(RuntimeException::class);

        new Centimeter(-1);
    }

    #[Test]
    public function meters_can_be_converted_to_float(): void
    {
        $meters = 1.5;
        $measure = new Meter($meters);

        $this->assertEquals($meters, $measure->asFloat());
    }

    #[Test]
    public function meters_can_be_converted_to_centimeters(): void
    {
        $measure = new Meter(1.53);

        $this->assertEquals(new Centimeter(153), $measure->asCentimeter());
    }

    #[Test]
    public function meters_cannot_be_negative(): void
    {
        $this->expectException(RuntimeException::class);

        new Meter(-1);
    }
}
MeasurementsTest.php
<?php declare(strict_types=1);

class Centimeter
{
    private readonly int $centimeters;

    public function __construct(int $centimeters)
    {
        $this->ensureNotNegative($centimeters);

        $this->centimeters = $centimeters;
    }

    public function asInt(): int
    {
        return $this->centimeters;
    }

    public function asMeter(): Meter
    {
        return new Meter($this->centimeters / 100);
    }

    private function ensureNotNegative(int $centimeters): void
    {
        if ($centimeters < 0) {
            throw new RuntimeException('Measure cannot be negative');
        }
    }
}
Centimeter.php
<?php declare(strict_types=1);

class Meter
{
    private readonly float $meters;

    public function __construct(float $meters)
    {
        $this->ensureNotNegative($meters);

        $this->meters = $meters;
    }

    public function asFloat(): float
    {
        return $this->meters;
    }

    public function asCentimeter(): Centimeter
    {
        return new Centimeter((int) ($this->meters * 100));
    }

    private function ensureNotNegative(float $meters): void
    {
        if ($meters < 0) {
            throw new RuntimeException('Measure cannot be negative');
        }
    }
}
Meter.php