30.10.26
⚡ Erreur permission PostgreSQL : tests Laravel (1 fix)13 min de lecture2 550 mots

⚡ Erreur permission PostgreSQL : tests Laravel (1 fix)

Erreur permission PostgreSQL sous Laravel : découvrez comment corriger les droits du schéma, isoler la base de test et fiabiliser PHPUnit. Fix rapide !

erreur permission PostgreSQL Laraveltests Laravel PHPUnit PostgreSQLbase de test Laraveldroits schéma PostgreSQLRefreshDatabase Laravel
⚡ Erreur permission PostgreSQL : tests Laravel (1 fix)

Résoudre une erreur de permission PostgreSQL dans les tests Laravel

Un test Laravel échoue parfois avant même de toucher au code qu'il est censé vérifier. Dans le journal, PostgreSQL indique que l'utilisateur n'a pas le droit de créer une table dans le schéma public. Le truc qui déroute, c'est que l'application arrive à se connecter à la base... mais Laravel plante quand il essaie de créer sa table migrations.

Ce cas rappelle une nuance importante : avoir accès à une base PostgreSQL ne veut pas dire automatiquement pouvoir y créer des tables. Les droits s'appliquent à plusieurs niveaux, et les migrations ont besoin d'autorisations sur le schéma concerné. Et si les tests pointent sur une autre base que celle prévue (mauvaise config, cache, variables d'environnement...), vous pouvez aussi vous retrouver à modifier une base de développement par accident.

Voici une approche prudente : diagnostiquer l'origine exacte, isoler une base de test, corriger les permissions utiles, puis vérifier côté Laravel/PHPUnit. On regardera aussi ce que fait vraiment RefreshDatabase, comment interpréter un avertissement PHP à côté, et quoi faire après un premier test de migration.

Comprendre l'erreur de permission PostgreSQL

Dans un test Laravel, les migrations peuvent être lancées avant même que les assertions ne s'exécutent. Laravel doit alors créer (ou consulter) la table migrations, qui garde la trace des migrations déjà appliquées. Si le rôle PostgreSQL utilisé par les tests n'a pas les droits requis sur le schéma, l'exécution s'arrête avec une erreur du style :

SQLSTATE[42501]: Insufficient privilege: 7

ERROR: permission denied for schema public

SQL: create table "migrations" (...)

Le code 42501 indique un refus d'autorisation. Ce n'est ni un souci de syntaxe SQL côté test, ni un problème « mystérieux » dans le code : PostgreSQL bloque simplement la création de l'objet demandé.

Les droits PostgreSQL ne se limitent pas à la base

Il faut distinguer plusieurs étages :

  • La base de données : elle gère notamment la connexion et la création de schémas.
  • Le schéma : il contient les tables, séquences, vues... et c'est là que Laravel crée en général ses tables (souvent dans public si rien d'autre n'est configuré).
  • Les objets : chaque table (ou vue, séquence, etc.) a ses propres droits (lecture/écriture/suppression, etc.).

Donc oui, un rôle peut réussir à se connecter à samu_test et, malgré tout, ne pas avoir le droit de créer une table dans public. Donner CONNECT sur une base n'implique pas automatiquement CREATE sur chaque schéma qu'elle contient.

Dans beaucoup de setups, la base de test appartient à un compte admin (souvent postgres), alors que Laravel se connecte avec un rôle applicatif. Dans ce cas, il faut vérifier qui est propriétaire de quoi, et surtout quels droits ont réellement été accordés au rôle utilisé par Laravel.

Commencer par vérifier la configuration réelle

Avant de « bidouiller » les permissions, assurez-vous que l'échec vient bien du bon niveau PostgreSQL. Notez le nom de la base, le nom du rôle et le schéma visé par Laravel.

Une config approximative peut produire un diagnostic trompeur : les tests peuvent utiliser une valeur issue de phpunit.xml, de .env.testing ou d'une configuration mise en cache.

Vérifiez aussi que les tests ne pointent pas vers la base de développement. Une commande de migration, ou un trait de test qui remet la base à zéro, peut supprimer/recréer des tables. La logique simple : d'abord sécuriser la cible, ensuite corriger les droits. Et évitez de « tout corriger » en donnant tous les droits au compte utilisé partout : c'est pratique sur le moment, mais dangereux à long terme.

Pour les autorisations à l'échelle bases/schémas/objets, voir la documentation PostgreSQL sur les privilèges. Les droits « par défaut » liés à public peuvent changer selon la version et la configuration : ne partez pas du principe qu'un rôle a toujours le même comportement.

Créer une base de test et régler les droits

Les tests automatisés peuvent lancer des migrations, utiliser des transactions et remettre la base dans un état connu. Ils ne doivent donc pas utiliser la base de développement (encore moins une base de production). Créez une base dédiée, par exemple samu_test, et configurez Laravel pour ne s'y connecter que pendant les tests.

Cette séparation aide autant côté sécurité que côté reproductibilité : vous évitez qu'une migration ou un nettoyage de données touche un environnement utilisé ailleurs.

Examiner la base et son propriétaire

Sur une machine où vous pouvez utiliser postgres avec sudo, listez les bases :

sudo -u postgres psql -l

Exemple :

Name       | Owner

-----------+----------

postgres | postgres

samu | samu_user

samu_test | postgres

Ici, samu_test existe, mais son propriétaire est postgres. Ce n'est pas forcément une erreur : ça veut surtout dire que le rôle applicatif (samu_user) ne possède pas automatiquement tous les droits nécessaires sur cette base.

Vérifiez aussi le propriétaire et les privilèges du schéma public :

sudo -u postgres psql -d samu_test -c "\dn+ public"

Cette commande permet de voir s'il y a un décalage entre le propriétaire de la base, celui du schéma, et le rôle utilisé par Laravel.

Propriété et/ou permissions explicites

Pour une base dédiée uniquement aux tests, une option simple consiste à donner au rôle applicatif la propriété de la base et du schéma :

sudo -u postgres psql -c \

"ALTER DATABASE samu_test OWNER TO samu_user;"

sudo -u postgres psql -d samu_test -c \

"ALTER SCHEMA public OWNER TO samu_user;"

Ces commandes exigent un rôle autorisé à modifier les propriétaires. Elles vont bien si vous avez décidé que samu_user doit administrer cette base de test. En revanche, ne les appliquez pas « comme ça » sur une base partagée ou un environnement plus critique.

Autre approche : garder un propriétaire distinct et accorder les permissions nécessaires au rôle applicatif. Par exemple :

GRANT CONNECT ON DATABASE samu_test TO samu_user;

GRANT USAGE, CREATE ON SCHEMA public TO samu_user;

  • CONNECT permet de se connecter à la base.
  • USAGE donne le droit d'utiliser le schéma.
  • CREATE autorise la création d'objets dans ce schéma.

À adapter selon votre politique d'accès. Et surtout : exécutez les droits au bon niveau (ce n'est pas le même endroit pour les droits de base et pour ceux du schéma).

L'idée n'est pas d'ouvrir tous les privilèges possibles : donnez au rôle de test exactement ce dont les migrations ont besoin sur la base dédiée. Et évitez d'utiliser postgres comme compte permanent de l'application : ça masque le problème au lieu de le corriger et rend plus probable un impact en cas de mauvaise cible.

Configurer PHPUnit et préparer la base avec Laravel

Ensuite, vérifiez que PHPUnit et Laravel utilisent bien les mêmes paramètres. Le nom de la base doit être identique partout : config Laravel, phpunit.xml, et variables d'environnement utilisées pendant l'exécution. Sinon, corriger les permissions ne sert à rien si vos tests ne pointent pas sur la bonne base.

Définir la connexion de test

Dans phpunit.xml, vous pouvez définir les variables d'environnement pour l'exécution « testing » :

<env name="APP_ENV" value="testing"/>

<env name="DB_CONNECTION" value="pgsql"/>

<env name="DB_HOST" value="127.0.0.1"/>

<env name="DB_PORT" value="5432"/>

<env name="DB_DATABASE" value="samu_test"/>

<env name="DB_USERNAME" value="samu_user"/>

Rappel rapide :

Paramètre Rôle
APP_ENV Indique à Laravel qu'il est en environnement de test.
DB_CONNECTION Pilote PostgreSQL (pgsql).
DB_HOST Adresse du serveur.
DB_PORT Port PostgreSQL (souvent 5432).
DB_DATABASE Base dédiée aux tests.
DB_USERNAME Rôle utilisé par Laravel.

Si l'authentification nécessite un mot de passe, ajoutez aussi le secret via le mécanisme approprié à votre environnement (variables protégées, gestionnaire de secrets, config locale exclue du dépôt, etc.).

Laravel peut aussi charger .env.testing. Vérifiez qu'il ne contient pas des valeurs contradictoires avec phpunit.xml, notamment DB_DATABASE et DB_USERNAME. Après une modif, pensez à vider le cache de configuration :

php artisan config:clear

La documentation Laravel sur les tests et celle sur la configuration des bases de données décrivent le comportement selon la version. Le point pratique : ne supposez pas que « votre intention » est ce qui est chargé. Regardez ce qui est effectivement utilisé.

Utiliser RefreshDatabase avec un objectif clair

Le trait RefreshDatabase aide à remettre la base dans un état cohérent entre tests. Selon votre configuration, il peut s'appuyer sur les migrations et des transactions pour isoler les opérations. Mais il ne « répare » pas les permissions PostgreSQL : si le rôle n'a pas le droit de créer les tables nécessaires, RefreshDatabase échouera aussi.

Exemple de test qui vérifie qu'une migration de table est bien enregistrée :

<?php

namespace Tests\Feature;

use Illuminate\Foundation\Testing\RefreshDatabase;

use Tests\TestCase;

class MenuCategoryApiTest extends TestCase

{

use RefreshDatabase;

public function test_menu_categories_table_exists(): void

{

$this->assertDatabaseHas('migrations', [

'migration' => '2026_09_18_034452_create_menu_categories_table',

]);

}

}

Ce test vérifie qu'une ligne existe dans l'historique des migrations, et que le nom correspond exactement à celui du fichier de migration. Il ne vérifie pas, à lui seul, que toutes les colonnes et contraintes sont correctes.

RefreshDatabase est super quand chaque test doit démarrer d'un état maîtrisé. Mais l'utiliser sans comprendre son effet peut ralentir la suite, ou provoquer des surprises si la connexion cible n'est pas celle que vous pensiez. Avant d'ajouter le trait, confirmez au moins l'environnement, le nom de la base, et le comportement attendu de vos migrations.

Vérifier le résultat et poursuivre les tests

Une fois les droits et la config PHPUnit corrigés, relancez un test ciblé :

php artisan config:clear

php artisan test --filter=MenuCategoryApiTest

Si ça passe, vous avez déjà la preuve que :

  • Laravel a utilisé la connexion attendue,
  • il a pu accéder à la base,
  • et l'assertion du test s'est exécutée.

Ça ne garantit pas que tous les parcours de l'API fonctionnent, ni que chaque contrainte de données est correcte. C'est une étape de diagnostic, pas une validation complète.

Distinguer le problème PostgreSQL des avertissements PHP

Il arrive aussi que le test « passe » tout en affichant un avertissement de dépréciation PHP provenant d'une dépendance, par exemple nunomaduro/collision. Un message sur un paramètre « implicitement nullable » ne parle pas de permissions PostgreSQL : ce sont deux problèmes séparés.

Pour trier le vrai du bruit, relevez les versions :

php -v

composer show nunomaduro/collision

composer show laravel/framework

composer show phpunit/phpunit

Avant de mettre à jour un paquet, vérifiez la compatibilité avec votre version de Laravel, PHPUnit et PHP. Une mise à jour « au hasard » peut faire disparaître un avertissement... tout en introduisant un souci ailleurs. En pratique : traitez d'abord les erreurs bloquantes, puis revenez sur les avertissements.

Tester le comportement métier, pas seulement l'existence d'une table

Vérifier que la table migrations contient la migration attendue est utile pour valider la chaîne de préparation de la base. Mais pour une API de catégories de menu, vous voulez des tests qui collent au comportement réel exposé.

Par exemple :

Cas à tester Résultat attendu
Lister les catégories La réponse contient les données attendues et le bon code HTTP.
Créer une catégorie Une donnée valide est enregistrée et renvoyée correctement.
Valider les entrées Une donnée invalide est rejetée avec les erreurs attendues.
Afficher une catégorie La ressource demandée est renvoyée, ou une réponse adaptée si elle n'existe pas.
Modifier une catégorie Les changements sont persistés et visibles dans la réponse.
Supprimer une catégorie L'enregistrement est supprimé conformément aux règles de l'API.
Gérer les doublons Les règles d'unicité du produit sont respectées.
Vérifier les relations Les références vers un entrepôt ou une section de cuisine sont correctes.

Vous pouvez aussi tester les migrations (colonnes, clés étrangères, contraintes). Puis lancez la suite complète avec php artisan test, idéalement dans un environnement CI configuré pareil. Si vous exécutez en parallèle, assurez-vous aussi que le mécanisme de séparation des bases/données entre processus est en place : chaque exécution doit avoir son espace.

Enfin, en production, n'importez pas « tel quel » les droits utilisés en test. Un rôle capable de créer des tables est pratique pour les migrations, mais une application en fonctionnement a souvent besoin de droits plus limités. Les besoins ne sont pas les mêmes entre migration, exécution de l'application et tests automatisés : ces étapes n'ont pas à partager le même compte.

Questions frequentes

La connexion à la base et la création d’objets relèvent de permissions distinctes. Le rôle peut avoir le droit CONNECT sur la base, mais pas le droit CREATE dans le schéma public. Vérifiez les droits du schéma utilisé par les migrations, pas seulement ceux de la base.
Non. Il est préférable d’utiliser un rôle applicatif dédié et suffisamment autorisé sur une base de test distincte. Employer le superutilisateur peut faire disparaître l’erreur, mais masque une configuration de permissions incorrecte et augmente le risque d’impact en cas de mauvaise cible.
Non. RefreshDatabase aide Laravel à préparer et isoler l’état de la base pour les tests. Il ne modifie pas les droits PostgreSQL. Le rôle configuré doit déjà pouvoir accéder à la base et effectuer les opérations de migration requises dans le schéma concerné.
Un avertissement de dépréciation émis par une dépendance est différent d’une erreur de base de données. Il signale généralement un sujet de compatibilité entre PHP et le paquet concerné. Vérifiez les versions installées, puis choisissez une mise à jour compatible avec le framework et PHPUnit du projet.

Articles similaires