5

  1. Schreibe eine equals()-Methode, um zwei Längenmaße miteinander zu vergleichen.

Hierfür legen wir einen neuen Testfall an, damit das Ganze übersichtlich bleibt. Es gibt vier verschiedene Fälle, die wir betrachten müssen, und zwar den Vergleich von Zentimetern miteinander, den Vergleich von Metern miteinander sowie den Vergleich von Metern mit Zentimetern und umgekehrt.

Normalerweise würde ich beim TDD die Testfälle einzeln nacheinander hinschreiben, aber ich will Dir ersparen, Dich durch so viele Lösungen zu klicken. Daher kommen hier alle vier Testfälle auf einmal:

<?php declare(strict_types=1);

namespace spriebsch\tfd\designPatterns\valueObject\measureOfLength\comparison;

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

#[CoversClass(Meter::class)]
#[CoversClass(Centimeter::class)]
class CompareMeasurementsTest extends TestCase
{
    #[Test]
    public function meters_can_be_compared(): void
    {
        $meter = new Meter(1.23);

        $this->assertTrue($meter->equals($meter));
        $this->assertFalse($meter->equals(new Meter(1.24)));
    }

    #[Test]
    public function centimeters_can_be_compared(): void
    {
        $centimeter = new Centimeter(142);

        $this->assertTrue($centimeter->equals($centimeter));
        $this->assertFalse($centimeter->equals(new Centimeter(197)));
    }

    #[Test]
    public function centimeters_can_be_compared_with_meters(): void
    {
        $centimeter = new Centimeter(142);
        $meter = new Meter(1.42);

        $this->assertTrue($centimeter->equals($meter));
        $this->assertFalse($centimeter->equals(new Meter(1.97)));
    }

    #[Test]
    public function meters_can_be_compared_with_centimeters(): void
    {
        $centimeter = new Centimeter(142);
        $meter = new Meter(1.42);

        $this->assertTrue($meter->equals($centimeter));
        $this->assertFalse($meter->equals(new Centimeter(197)));
    }

    #[Test]
    public function exception_when_comparing_centimeter_to_unsupported_measure(): void
    {
        $centimeter = new Centimeter(142);
        $unsupportedMeasurement = $this->createMock(Measurement::class);

        $this->expectException(RuntimeException::class);

        $centimeter->equals($unsupportedMeasurement);
    }

    #[Test]
    public function exception_when_comparing_meter_to_unsupported_measure(): void
    {
        $meter = new Meter(1.42);
        $unsupportedMeasurement = $this->createMock(Measurement::class);

        $this->expectException(RuntimeException::class);

        $meter->equals($unsupportedMeasurement);
    }
}
CompareMeasurementsTest.php

Warte mal, da stehen ja sechs verschiedene Fälle. Das liegt daran, dass wir bisher gewissermaßen Äpfel und Birnen miteinander verglichen haben, denn die Klassen Centimeter und Meter hatten außer struktureller Ähnlichkeit nichts gemeinsam. Für die Signatur einer einheitlichen equals()-Methode brauchen wir aber eine Gemeinsamkeit, deshalb mussten wir das Interface Measurement einführen:

<?php declare(strict_types=1);

namespace spriebsch\tfd\designPatterns\valueObject\measureOfLength\comparison;
interface Measurement
{
    public function equals(Measurement $measurement): bool;
}
Measurement.php

Da wir damit nicht mehr nur auf Centimeter und Meter festgelegt sind, weil ja irgendwer in Zukunft weitere Implementierungen von Measurement erstellen kann, müssen wir uns überlegen, was passiert, wenn wir mit einem solchen neuen Measurement vergleichen. Wir wissen ja noch nicht, wie wir das umrechnen müssen. Falls das jetzt gerade verwirrend war, es wird weiter unten gleich klar.

Erst mal die letzten beiden Testfälle:

$this->assertFalse($meter->equals(new Centimeter(197)));
    }

    #[Test]
    public function exception_when_comparing_centimeter_to_unsupported_measure(): void
    {
$centimeter = new Centimeter(142);
$unsupportedMeasurement = $this->createMock(Measurement::class);

$this->expectException(RuntimeException::class);

$centimeter->equals($unsupportedMeasurement);
    }

    #[Test]
    public function exception_when_comparing_meter_to_unsupported_measure(): void
    {
$meter = new Meter(1.42);
$unsupportedMeasurement = $this->createMock(Measurement::class);

$this->expectException(RuntimeException::class);
CompareMeasurementsTest.php

Wir mocken uns in diesen Tests einfach jeweils ein Measurement. Okay, streng genommen sind das Stubs und keine Mocks, aber man ist da im Alltag oft relativ schlampig mit diesen Bezeichnungen. Wichtig ist, dass wir dem Interface Segregation-Prinzip folgen.

@@@CTA@@@