createMock(HubInterface::class); $hub->expects($this->once()) ->method('publish') ->willReturnCallback(function (Update $u) use (&$captured) { $captured = $u; return 'urn:uuid:test'; }); $publisher = new MercurePublisher($hub, new NullLogger()); $publisher->publishDevice(42, ['id' => 42, 'name' => 'Living Room']); $this->assertNotNull($captured); $this->assertSame( ['https://pictureframe.edholm.me/devices/42'], $captured->getTopics(), ); $this->assertSame('{"id":42,"name":"Living Room"}', $captured->getData()); } public function test_swallows_hub_exceptions_so_callers_never_blow_up(): void { $hub = $this->createMock(HubInterface::class); $hub->method('publish')->willThrowException(new \RuntimeException('hub down')); $publisher = new MercurePublisher($hub, new NullLogger()); // No exception should escape — if this throws, the test fails. $publisher->publishDevice(42, ['id' => 42]); $this->expectNotToPerformAssertions(); } }