diff --git a/composer.json b/composer.json
index 508ebde94d25fd800492e59ab43b11d040a8a59e..5e13d57282a62d027874f3051a967c7ce65df7fa 100644
--- a/composer.json
+++ b/composer.json
@@ -7,10 +7,16 @@
         "MIT"
     ],
     "autoload": {
-        "psr-4": { "Spip\\Core\\Testing\\": "src/" }
+        "psr-4": {
+            "Spip\\Core\\Testing\\": "src/"
+        }
     },
     "autoload-dev": {
-        "psr-4": { "Spip\\Core\\Tests\\": "tests/" }
+        "psr-4": {
+            "Spip\\Core\\Tests\\": "tests/",
+            "Utils\\Rector\\": "utils/rector/src",
+            "Utils\\Rector\\Tests\\": "utils/rector/tests"
+        }
     },
     "require": {
         "php": ">=7.4.0",
@@ -24,6 +30,7 @@
     "require-dev": {
         "lolli42/finediff": "^1.0",
         "phpunit/phpunit": "^8.3 || ^9.4",
+        "rector/rector": "^0.14.1",
         "symfony/var-dumper": "^5.4 || ^6"
     },
     "repositories": [
diff --git a/rector.php b/rector.php
new file mode 100644
index 0000000000000000000000000000000000000000..abe870d8420b4052b21f196e3ad732641f20bd30
--- /dev/null
+++ b/rector.php
@@ -0,0 +1,35 @@
+<?php
+
+declare(strict_types=1);
+
+use Rector\CodeQuality\Rector\Class_\InlineConstructorDefaultToPropertyRector;
+use Rector\Config\RectorConfig;
+use Rector\Set\ValueObject\LevelSetList;
+use Rector\Set\ValueObject\SetList;
+use Rector\CodingStyle\Rector\Encapsed\EncapsedStringsToSprintfRector;
+use Utils\Rector\Rector\Set\ValueObject\SpipTestSetList;
+
+return static function (RectorConfig $rectorConfig): void {
+    $rectorConfig->paths([
+        __DIR__ . '/src',
+        __DIR__ . '/tests'
+    ]);
+
+    // register a single rule
+    // $rectorConfig->rule(InlineConstructorDefaultToPropertyRector::class);
+
+    // define sets of rules
+	$rectorConfig->sets([
+		SpipTestSetList::ESSAIS_MIGRATION
+	]);
+	/*
+    $rectorConfig->sets([
+		SetList::CODE_QUALITY,
+		SetList::CODING_STYLE,
+        LevelSetList::UP_TO_PHP_74
+    ]);
+
+	$rectorConfig->skip([
+		EncapsedStringsToSprintfRector::class
+	]);*/
+};
diff --git a/utils/rector/config/set/spip_test_essais_migration.php b/utils/rector/config/set/spip_test_essais_migration.php
new file mode 100644
index 0000000000000000000000000000000000000000..4ee3eac87009705227e6ddf5db348eab66923892
--- /dev/null
+++ b/utils/rector/config/set/spip_test_essais_migration.php
@@ -0,0 +1,12 @@
+<?php
+
+declare (strict_types=1);
+namespace RectorPrefix202209;
+
+use Rector\Config\RectorConfig;
+use Utils\Rector\Rector\RefactorSpipTestsEssais;
+
+return static function (RectorConfig $rectorConfig) : void {
+	// nothing
+	$rectorConfig->rule(RefactorSpipTestsEssais::class);
+};
diff --git a/utils/rector/src/Rector/RefactorSpipTestsEssais.php b/utils/rector/src/Rector/RefactorSpipTestsEssais.php
new file mode 100644
index 0000000000000000000000000000000000000000..73018af1a1c93f52f6b174501b6ac4d5679a4649
--- /dev/null
+++ b/utils/rector/src/Rector/RefactorSpipTestsEssais.php
@@ -0,0 +1,181 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Utils\Rector\Rector;
+
+use Nette\Utils\Strings;
+use PhpParser\Builder\Method as MethodBuilder;
+use PhpParser\Builder\Use_ as UseBuilder;
+use PhpParser\Node;
+use PhpParser\Node\Expr\MethodCall;
+use PhpParser\Node\Identifier;
+use PhpParser\Node\Name;
+use PhpParser\Node\Name\FullyQualified;
+use PhpParser\Node\Stmt\Namespace_;
+use PhpParser\Node\Stmt\Class_;
+use PhpParser\Node\Stmt\Expression;
+use PhpParser\Node\Stmt\Function_;
+use Rector\Core\NodeManipulator\ClassInsertManipulator;
+use Rector\Core\Rector\AbstractRector;
+use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample;
+use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;
+use RectorPrefix202209\Symfony\Component\String\UnicodeString;
+use PhpParser\Node\Stmt\Use_;
+use Rector\Core\Application\FileSystem\RemovedAndAddedFilesCollector;
+use Rector\Core\PhpParser\Node\NodeFactory;
+
+final class RefactorSpipTestsEssais extends AbstractRector
+{
+	private string $namespace = 'Spip\\Core\\Tests';
+
+	/**
+	 * @readonly
+	 * @var \Rector\Core\NodeManipulator\ClassInsertManipulator
+	 */
+	private $classInsertManipulator;
+
+	/**
+     * @readonly
+     * @var \Rector\Core\Application\FileSystem\RemovedAndAddedFilesCollector
+     */
+    private $removedAndAddedFilesCollector;
+
+	public function __construct(ClassInsertManipulator $classInsertManipulator, RemovedAndAddedFilesCollector $removedAndAddedFilesCollector)
+	{
+		$this->classInsertManipulator = $classInsertManipulator;
+		$this->removedAndAddedFilesCollector = $removedAndAddedFilesCollector;
+	}
+
+	/**
+	 * @return array<class-string<Node>>
+	 */
+	public function getNodeTypes(): array
+	{
+		return [Namespace_::class];
+	}
+
+	/**
+	 * @param MethodCall $node - we can add "MethodCall" type here, because
+	 *                         only this node is in "getNodeTypes()"
+	 */
+	public function refactor(Node $node): ?Node
+	{
+
+		$fqdn = $this->getFqdn();
+		$newNamespace = $fqdn->slice(0, -1)->toString();
+		$this->isChangedInNamespaces[$newNamespace] = \true;
+		$node->name = new Name($newNamespace);
+
+		$uses = [
+			(new UseBuilder('PHPUnit\\Framework\\TestCase', Use_::TYPE_NORMAL))->getNode()
+		];
+
+		$class = $this->createTestClass($fqdn->getLast());
+		$class->namespacedName = $node->name;
+
+		$setUpMethod = $this->createPublicStaticMethod('setUpBeforeClass');
+		$this->classInsertManipulator->addAsFirstMethod($class, $setUpMethod);
+
+		foreach ($node->stmts as $key => $stmt) {
+			if ($stmt instanceof Expression) {
+				$setUpMethod->stmts[] = $stmt;
+			} elseif ($stmt instanceof Function_) {
+				$method = $this->createPublicMethod($stmt->name->toString());
+				$method->stmts = $stmt->stmts;
+				$class->stmts[] = $method;
+			}
+		}
+
+		$node->stmts = [
+			...$uses,
+			$class,
+		];
+
+		$this->renameFile($fqdn);
+		return $node;
+
+	}
+
+	/**
+	 * This method helps other to understand the rule and to generate documentation.
+	 */
+	public function getRuleDefinition(): RuleDefinition
+	{
+		return new RuleDefinition(
+			'Move essais/*.php to PHPUnit.',
+			[
+				new CodeSample(
+					<<<CODESAMPLE
+					function test_connect_sql_id_table_objet(...\$args) {
+						return id_table_objet(...\$args);
+					}
+					// ...
+					CODESAMPLE,
+					<<<CODESAMPLE
+					class IdTableObjetTest extends TestCase {
+						function testIdTableObjet(\$expected, ...\$args) {
+							\$this->expectEquals(\$expected, id_table_objet(...\$args));
+						}
+						// ...
+					}
+					CODESAMPLE,
+				),
+			]
+		);
+	}
+
+	private function getFqdn(): FullyQualified
+	{
+		$filePath = $this->file->getFilePath();
+		$dirname = basename(\pathinfo($filePath, \PATHINFO_DIRNAME));
+		$basename = \pathinfo($filePath, \PATHINFO_FILENAME);
+
+		$dir = new UnicodeString($dirname);
+		$dir = ucfirst($dir->camel()->toString());
+
+		$file = new UnicodeString($basename);
+		$file = ucfirst($file->camel()->toString()) . 'Test';
+
+		return new FullyQualified($this->namespace . "\\Essais\\$dir\\$file");
+	}
+
+	/** @see https://github.com/rectorphp/rector/blob/main/rules/Restoration/Rector/ClassLike/UpdateFileNameByClassNameFileSystemRector.php */
+	private function renameFile(FullyQualified $namespace): void {
+		$filePath = $this->file->getFilePath();
+
+		$newPath = $namespace->slice(3)->toString();
+
+		$filePath = $this->file->getFilePath();
+		$newFileLocation = \dirname($filePath) . \DIRECTORY_SEPARATOR . $newPath . '.php';
+
+		$this->removedAndAddedFilesCollector->addMovedFile($this->file, $newFileLocation);
+	}
+
+
+	private function createTestClass(string $name): Class_
+	{
+		$class = new Class_($name);
+
+		$class->extends = new FullyQualified('TestCase');
+
+		return $class;
+	}
+
+	private function createPublicStaticMethod($name)
+	{
+		$method = new MethodBuilder($name);
+		$method->makePublic();
+		$method->makeStatic();
+		$method->setReturnType(new Identifier('void'));
+		return $method->getNode();
+	}
+
+	private function createPublicMethod($name)
+	{
+		$method = new MethodBuilder($name);
+		$method->makePublic();
+		$method->setReturnType(new Identifier('void'));
+		return $method->getNode();
+	}
+}
diff --git a/utils/rector/src/Rector/Set/ValueObject/SpipTestSetList.php b/utils/rector/src/Rector/Set/ValueObject/SpipTestSetList.php
new file mode 100644
index 0000000000000000000000000000000000000000..64aaac2f9b2ade53a576022b3a7f13e378736785
--- /dev/null
+++ b/utils/rector/src/Rector/Set/ValueObject/SpipTestSetList.php
@@ -0,0 +1,13 @@
+<?php
+
+declare (strict_types=1);
+namespace Utils\Rector\Rector\Set\ValueObject;
+
+use Rector\Set\Contract\SetListInterface;
+/**
+ * @api
+ */
+final class SpipTestSetList implements SetListInterface
+{
+	public const ESSAIS_MIGRATION = __DIR__ . '/../../../../config/set/spip_test_essais_migration.php';
+}