Step 00 — Squelette + intégration naïve
3 Bounded Contexts (Sales, Invoicing, LegacyFulfillment) avec : - Domaines complets (agrégats, VOs, événements, invariants) - Couche application (commands, queries, ports) - Infrastructure in-memory (repos, gateway fake) - Controllers HTTP Symfony - Couplage naïf synchrone entre BC via NaiveSalesEventPublisher - 20 tests unitaires et d'intégration passants
This commit is contained in:
122
tests/Unit/Sales/Domain/OrderTest.php
Normal file
122
tests/Unit/Sales/Domain/OrderTest.php
Normal file
@@ -0,0 +1,122 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace MiniShop\Tests\Unit\Sales\Domain;
|
||||
|
||||
use MiniShop\Sales\Domain\Event\OrderCancelled;
|
||||
use MiniShop\Sales\Domain\Event\OrderConfirmed;
|
||||
use MiniShop\Sales\Domain\Event\OrderPlaced;
|
||||
use MiniShop\Sales\Domain\Exception\EmptyOrderException;
|
||||
use MiniShop\Sales\Domain\Exception\InvalidOrderStateException;
|
||||
use MiniShop\Sales\Domain\Model\CustomerId;
|
||||
use MiniShop\Sales\Domain\Model\Money;
|
||||
use MiniShop\Sales\Domain\Model\Order;
|
||||
use MiniShop\Sales\Domain\Model\OrderId;
|
||||
use MiniShop\Sales\Domain\Model\OrderLine;
|
||||
use MiniShop\Sales\Domain\Model\OrderStatus;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
final class OrderTest extends TestCase
|
||||
{
|
||||
public function test_place_order_with_lines(): void
|
||||
{
|
||||
$order = $this->placeOrder();
|
||||
|
||||
self::assertSame(OrderStatus::Placed, $order->status());
|
||||
self::assertCount(1, $order->lines());
|
||||
self::assertTrue($order->total()->isPositive());
|
||||
}
|
||||
|
||||
public function test_place_order_records_order_placed_event(): void
|
||||
{
|
||||
$order = $this->placeOrder();
|
||||
|
||||
$events = $order->releaseEvents();
|
||||
self::assertCount(1, $events);
|
||||
self::assertInstanceOf(OrderPlaced::class, $events[0]);
|
||||
}
|
||||
|
||||
public function test_place_order_without_lines_throws(): void
|
||||
{
|
||||
$this->expectException(EmptyOrderException::class);
|
||||
|
||||
Order::place(
|
||||
OrderId::fromString('order-1'),
|
||||
CustomerId::fromString('cust-1'),
|
||||
[],
|
||||
new \DateTimeImmutable(),
|
||||
);
|
||||
}
|
||||
|
||||
public function test_confirm_placed_order(): void
|
||||
{
|
||||
$order = $this->placeOrder();
|
||||
$order->releaseEvents();
|
||||
|
||||
$order->confirm();
|
||||
|
||||
self::assertSame(OrderStatus::Confirmed, $order->status());
|
||||
$events = $order->releaseEvents();
|
||||
self::assertCount(1, $events);
|
||||
self::assertInstanceOf(OrderConfirmed::class, $events[0]);
|
||||
}
|
||||
|
||||
public function test_confirm_draft_order_throws(): void
|
||||
{
|
||||
$this->expectException(InvalidOrderStateException::class);
|
||||
|
||||
$order = $this->placeOrder();
|
||||
$order->confirm();
|
||||
$order->releaseEvents();
|
||||
|
||||
$order->confirm(); // already confirmed
|
||||
}
|
||||
|
||||
public function test_cancel_placed_order(): void
|
||||
{
|
||||
$order = $this->placeOrder();
|
||||
$order->releaseEvents();
|
||||
|
||||
$order->cancel();
|
||||
|
||||
self::assertSame(OrderStatus::Cancelled, $order->status());
|
||||
$events = $order->releaseEvents();
|
||||
self::assertCount(1, $events);
|
||||
self::assertInstanceOf(OrderCancelled::class, $events[0]);
|
||||
}
|
||||
|
||||
public function test_cannot_cancel_confirmed_order(): void
|
||||
{
|
||||
$this->expectException(InvalidOrderStateException::class);
|
||||
|
||||
$order = $this->placeOrder();
|
||||
$order->confirm();
|
||||
$order->cancel();
|
||||
}
|
||||
|
||||
public function test_total_is_sum_of_line_totals(): void
|
||||
{
|
||||
$order = Order::place(
|
||||
OrderId::fromString('order-1'),
|
||||
CustomerId::fromString('cust-1'),
|
||||
[
|
||||
new OrderLine('Widget', 2, new Money(1000, 'EUR')),
|
||||
new OrderLine('Gadget', 1, new Money(2500, 'EUR')),
|
||||
],
|
||||
new \DateTimeImmutable(),
|
||||
);
|
||||
|
||||
self::assertTrue($order->total()->equals(new Money(4500, 'EUR')));
|
||||
}
|
||||
|
||||
private function placeOrder(): Order
|
||||
{
|
||||
return Order::place(
|
||||
OrderId::fromString('order-1'),
|
||||
CustomerId::fromString('cust-1'),
|
||||
[new OrderLine('Widget', 2, new Money(1500, 'EUR'))],
|
||||
new \DateTimeImmutable(),
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user