Paillasse/portail/tests/Feature/OptimisationMariadbTest.php

64 lines
3.1 KiB
PHP
Raw Normal View History

<?php
use App\Models\Classe;
use App\Models\Correction;
use App\Models\Eleve;
use App\Models\Lab;
use App\Models\LabSession;
use App\Models\Observation;
use App\Models\Seance;
use App\Models\User;
use Illuminate\Support\Facades\DB;
/**
* Bloc B, optimisation MariaDB (2026-10-14) : « Résultats » faisait une
* requête de corrections et une d'observations PAR classe — un N+1
* classique. Vérifié en comptant les vraies requêtes SQL, pas en devinant :
* le nombre doit rester le même, que le prof ait 1 classe ou 5.
*/
function resultatsPourProfAvecNClasses($test, int $nombreClasses): int
{
$prof = User::factory()->create();
for ($i = 0; $i < $nombreClasses; $i++) {
$classe = Classe::factory()->create(['user_id' => $prof->id]);
$eleve = Eleve::factory()->create(['classe_id' => $classe->id]);
$seance = Seance::create(['classe_id' => $classe->id, 'lab_id' => Lab::factory()->create()->id, 'statut' => Seance::TERMINEE]);
$labSession = LabSession::create(['seance_id' => $seance->id, 'eleve_id' => $eleve->id, 'lab_id' => $seance->lab_id, 'etat' => LabSession::TERMINE]);
Correction::create(['lab_session_id' => $labSession->id, 'reussi' => true, 'note' => 8, 'note_max' => 10, 'details' => []]);
Observation::create(['classe_id' => $classe->id, 'eleve_id' => $eleve->id, 'user_id' => $prof->id, 'contenu' => 'Observation de test']);
}
$requetes = 0;
DB::listen(function () use (&$requetes) {
$requetes++;
});
prof($test, $prof)->get(route('resultats'))->assertOk();
return $requetes;
}
test('le nombre de requêtes de /resultats ne dépend pas du nombre de classes (pas de N+1)', function () {
$requetesUneClasse = resultatsPourProfAvecNClasses($this, 1);
$requetesCinqClasses = resultatsPourProfAvecNClasses($this, 5);
expect($requetesCinqClasses)->toBe($requetesUneClasse);
});
test('les corrections et observations affichées restent correctes après le regroupement en lot', function () {
$prof = User::factory()->create();
$classeA = Classe::factory()->create(['user_id' => $prof->id, 'nom' => 'Classe A']);
$classeB = Classe::factory()->create(['user_id' => $prof->id, 'nom' => 'Classe B']);
$seanceA = Seance::create(['classe_id' => $classeA->id, 'lab_id' => Lab::factory()->create()->id, 'statut' => Seance::TERMINEE]);
$eleveA = Eleve::factory()->create(['classe_id' => $classeA->id, 'prenom' => 'Alice']);
$labSessionA = LabSession::create(['seance_id' => $seanceA->id, 'eleve_id' => $eleveA->id, 'lab_id' => $seanceA->lab_id, 'etat' => LabSession::TERMINE]);
Correction::create(['lab_session_id' => $labSessionA->id, 'reussi' => true, 'note' => 9, 'note_max' => 10, 'details' => []]);
Observation::create(['classe_id' => $classeA->id, 'eleve_id' => $eleveA->id, 'user_id' => $prof->id, 'contenu' => 'Bonne participation']);
// Classe B : aucune activité, ne doit jamais récupérer les données de la classe A.
$page = prof($this, $prof)->get(route('resultats'));
$page->assertOk()->assertSeeInOrder(['Classe A', '1 correction(s)', 'Bonne participation', 'Classe B', '0 correction(s)']);
});