evaluationRepository = new InMemoryEvaluationRepository(); $this->gradeRepository = new InMemoryGradeRepository(); $this->clock = new class implements Clock { public function now(): DateTimeImmutable { return new DateTimeImmutable('2026-03-27 14:00:00'); } }; $this->seedEvaluation(); } #[Test] public function itPublishesGradesWhenGradesExist(): void { $this->seedGrade(); $handler = $this->createHandler(); $command = new PublishGradesCommand( tenantId: self::TENANT_ID, evaluationId: self::EVALUATION_ID, teacherId: self::TEACHER_ID, ); $evaluation = $handler($command); self::assertTrue($evaluation->notesPubliees()); self::assertEquals( new DateTimeImmutable('2026-03-27 14:00:00'), $evaluation->gradesPublishedAt, ); } #[Test] public function itPersistsPublishedEvaluation(): void { $this->seedGrade(); $handler = $this->createHandler(); $handler(new PublishGradesCommand( tenantId: self::TENANT_ID, evaluationId: self::EVALUATION_ID, teacherId: self::TEACHER_ID, )); $evaluation = $this->evaluationRepository->get( EvaluationId::fromString(self::EVALUATION_ID), TenantId::fromString(self::TENANT_ID), ); self::assertTrue($evaluation->notesPubliees()); } #[Test] public function itThrowsWhenNoGradesExist(): void { $handler = $this->createHandler(); $this->expectException(AucuneNoteSaisieException::class); $handler(new PublishGradesCommand( tenantId: self::TENANT_ID, evaluationId: self::EVALUATION_ID, teacherId: self::TEACHER_ID, )); } #[Test] public function itThrowsWhenTeacherNotOwner(): void { $this->seedGrade(); $handler = $this->createHandler(); $otherTeacher = '550e8400-e29b-41d4-a716-446655440099'; $this->expectException(NonProprietaireDeLEvaluationException::class); $handler(new PublishGradesCommand( tenantId: self::TENANT_ID, evaluationId: self::EVALUATION_ID, teacherId: $otherTeacher, )); } #[Test] public function itThrowsWhenAlreadyPublished(): void { $this->seedGrade(); $handler = $this->createHandler(); $command = new PublishGradesCommand( tenantId: self::TENANT_ID, evaluationId: self::EVALUATION_ID, teacherId: self::TEACHER_ID, ); $handler($command); $this->expectException(NotesDejaPublieesException::class); $handler($command); } private function createHandler(): PublishGradesHandler { return new PublishGradesHandler( $this->evaluationRepository, $this->gradeRepository, $this->clock, ); } private function seedEvaluation(): void { $evaluation = Evaluation::reconstitute( id: EvaluationId::fromString(self::EVALUATION_ID), tenantId: TenantId::fromString(self::TENANT_ID), classId: ClassId::fromString('550e8400-e29b-41d4-a716-446655440020'), subjectId: SubjectId::fromString('550e8400-e29b-41d4-a716-446655440030'), teacherId: UserId::fromString(self::TEACHER_ID), title: 'ContrĂ´le chapitre 5', description: null, evaluationDate: new DateTimeImmutable('2026-04-15'), gradeScale: new GradeScale(20), coefficient: new Coefficient(1.0), status: EvaluationStatus::PUBLISHED, createdAt: new DateTimeImmutable('2026-03-12 10:00:00'), updatedAt: new DateTimeImmutable('2026-03-12 10:00:00'), ); $this->evaluationRepository->save($evaluation); } private function seedGrade(): void { $grade = Grade::saisir( tenantId: TenantId::fromString(self::TENANT_ID), evaluationId: EvaluationId::fromString(self::EVALUATION_ID), studentId: UserId::fromString(self::STUDENT_ID), value: new GradeValue(15.0), status: GradeStatus::GRADED, gradeScale: new GradeScale(20), createdBy: UserId::fromString(self::TEACHER_ID), now: new DateTimeImmutable('2026-03-27 10:00:00'), ); $this->gradeRepository->save($grade); } }