repository = $this->createMock(TaxonRepositoryInterface::class); $this->taxonUsageChecker = $this->createMock(TaxonUsageCheckerInterface::class); $this->service = new TaxonomyApplicationService( $this->repository, new CreateTaxon($this->repository, new TaxonSlugGenerator()), new DeleteTaxon($this->repository, $this->taxonUsageChecker), ); } // ── create ───────────────────────────────────────────────────── /** * create() doit générer le slug depuis le nom et persister le terme. */ public function testCreateGeneratesSlugAndPersists(): void { $this->repository->method('nameExists')->willReturn(false); $this->repository->expects($this->once()) ->method('create') ->with($this->callback( fn (Taxon $c) => $c->getName() === 'Développement web' && $c->getSlug() === 'developpement-web', )) ->willReturn(1); $id = $this->service->create('Développement web'); $this->assertSame(1, $id); } /** * create() doit trimmer le nom avant de générer le slug. */ public function testCreateTrimsName(): void { $this->repository->method('nameExists')->willReturn(false); $this->repository->expects($this->once()) ->method('create') ->with($this->callback(fn (Taxon $c) => $c->getName() === 'PHP')) ->willReturn(2); $this->service->create(' PHP '); } /** * create() doit lever InvalidArgumentException si le slug généré est vide. */ public function testCreateNonAsciiNameThrowsException(): void { $this->repository->expects($this->never())->method('create'); $this->expectException(\InvalidArgumentException::class); $this->expectExceptionMessage('slug URL valide'); $this->service->create('日本語'); } /** * create() doit lever InvalidArgumentException si le nom est existe déjà. */ public function testCreateDuplicateNameThrowsException(): void { $this->repository->method('nameExists')->willReturn(true); $this->repository->expects($this->never())->method('create'); $this->expectException(\InvalidArgumentException::class); $this->expectExceptionMessage('existe déjà'); $this->service->create('PHP'); } /** * create() doit lever InvalidArgumentException si le nom est vide. */ public function testCreateEmptyNameThrowsException(): void { $this->repository->method('nameExists')->willReturn(false); $this->repository->expects($this->never())->method('create'); $this->expectException(\InvalidArgumentException::class); $this->service->create(''); } /** * create() doit lever InvalidArgumentException si le nom dépasse 100 caractères. */ public function testCreateNameTooLongThrowsException(): void { $longName = str_repeat('a', 101); $this->repository->method('nameExists')->willReturn(false); $this->repository->expects($this->never())->method('create'); $this->expectException(\InvalidArgumentException::class); $this->service->create($longName); } // ── delete ───────────────────────────────────────────────────── /** * delete() doit supprimer le terme s'il n'est pas utilisé. */ public function testDeleteSucceedsWhenTaxonIsUnused(): void { $taxon = new Taxon(5, 'PHP', 'php'); $this->taxonUsageChecker->expects($this->once())->method('isTaxonInUse')->with(5)->willReturn(false); $this->repository->expects($this->once())->method('delete')->with(5); $this->service->delete($taxon); } /** * delete() doit lever InvalidArgumentException si le terme est encore utilisé. */ public function testDeleteBlockedWhenTaxonIsStillUsed(): void { $taxon = new Taxon(5, 'PHP', 'php'); $this->taxonUsageChecker->expects($this->once())->method('isTaxonInUse')->with(5)->willReturn(true); $this->repository->expects($this->never())->method('delete'); $this->expectException(\InvalidArgumentException::class); $this->expectExceptionMessage('est encore utilisé'); $this->service->delete($taxon); } // ── Lectures déléguées ───────────────────────────────────────── /** * findAll() doit déléguer au repository et retourner son résultat. */ public function testFindAllDelegatesToRepository(): void { $cats = [new Taxon(1, 'PHP', 'php'), new Taxon(2, 'CSS', 'css')]; $this->repository->method('findAll')->willReturn($cats); $this->assertSame($cats, $this->service->findAll()); } /** * findById() doit retourner null si le terme n'existe pas. */ public function testFindByIdReturnsNullWhenMissing(): void { $this->repository->method('findById')->willReturn(null); $this->assertNull($this->service->findById(99)); } /** * findBySlug() doit retourner le terme correspondant. */ public function testFindBySlugReturnsTaxonWhenFound(): void { $taxon = new Taxon(3, 'PHP', 'php'); $this->repository->expects($this->once())->method('findBySlug')->with('php')->willReturn($taxon); $this->assertSame($taxon, $this->service->findBySlug('php')); } }