repository = $this->createMock(CategoryRepositoryInterface::class); $this->service = new CategoryApplicationService($this->repository); } // ── create ───────────────────────────────────────────────────── /** * create() doit générer le slug depuis le nom et persister la catégorie. */ public function testCreateGeneratesSlugAndPersists(): void { $this->repository->method('nameExists')->willReturn(false); $this->repository->expects($this->once()) ->method('create') ->with($this->callback(fn (Category $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 (Category $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 déjà utilisé. */ public function testCreateDuplicateNameThrowsException(): void { $this->repository->method('nameExists')->willReturn(true); $this->repository->expects($this->never())->method('create'); $this->expectException(\InvalidArgumentException::class); $this->expectExceptionMessage('déjà utilisé'); $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 la catégorie si elle ne contient aucun article. */ public function testDeleteSucceedsWhenNoPosts(): void { $category = new Category(5, 'PHP', 'php'); $this->repository->expects($this->once())->method('hasPost')->with(5)->willReturn(false); $this->repository->expects($this->once())->method('delete')->with(5); $this->service->delete($category); } /** * delete() doit lever InvalidArgumentException si des articles sont rattachés. */ public function testDeleteBlockedWhenPostsAttached(): void { $category = new Category(5, 'PHP', 'php'); $this->repository->expects($this->once())->method('hasPost')->with(5)->willReturn(true); $this->repository->expects($this->never())->method('delete'); $this->expectException(\InvalidArgumentException::class); $this->expectExceptionMessage('contient des articles'); $this->service->delete($category); } // ── Lectures déléguées ───────────────────────────────────────── /** * findAll() doit déléguer au repository et retourner son résultat. */ public function testFindAllDelegatesToRepository(): void { $cats = [new Category(1, 'PHP', 'php'), new Category(2, 'CSS', 'css')]; $this->repository->method('findAll')->willReturn($cats); $this->assertSame($cats, $this->service->findAll()); } /** * findById() doit retourner null si la catégorie n'existe pas. */ public function testFindByIdReturnsNullWhenMissing(): void { $this->repository->method('findById')->willReturn(null); $this->assertNull($this->service->findById(99)); } /** * findBySlug() doit retourner la catégorie correspondante. */ public function testFindBySlugReturnsCategoryWhenFound(): void { $cat = new Category(3, 'PHP', 'php'); $this->repository->expects($this->once())->method('findBySlug')->with('php')->willReturn($cat); $this->assertSame($cat, $this->service->findBySlug('php')); } }