Flutter, IA et Tests : une nouvelle méthode pour coder plus vite et plus sûr

En 2025, l'arrivée massive des agents IA dans nos IDE a changé notre manière de coder. Mais sans un cadre solide, leur vitesse peut devenir un risque. Dans cet article, je te montre comment j'ai structuré un projet Flutter autour d'un trio gagnant : spécifications claires, tests automatisés, IA assistée. Résultat : un workflow plus fiable, plus rapide, et bien plus agréable.


1. Pourquoi j'ai revisité ma manière de coder en Flutter

Quand j'ai commencé Flutter, j'étais surtout focalisé sur l'UX/UI, les animations, la performance. Mais avec l'arrivée de l'IA, un nouveau défi est apparu :

Comment collaborer avec une IA sans mettre en danger la stabilité d'une l'app ?

Coder plus vite, c'est simple. Coder plus vite en toute confiance, c'est autre chose.

Et c'est là que j'ai redécouvert une vieille idée : pas de code sans intention claire.


2. Avant le code : définir les intentions (spec-driven development)

2.1. Pourquoi une spec avant tout ?

La plupart des prompts IA échouent parce que le contexte manque. L'IA doit deviner ce qu'on veut.

Quand tu précises tes intentions dans un fichier de spec, tu transformes ton workspace en un environnement explicite et maîtrisé.

Une spec peut contenir :

  • le descriptif des écrans et leur rôle
  • les flux utilisateurs
  • les règles métier
  • les cas limites
  • les erreurs à gérer
  • les contraintes techniques

Exemple minimal de spec :

# Story: Scan d'une carte Pokémon (PSA)

## Objectif

L'utilisateur scanne une carte Pokémon gradée PSA (via le QR code ou le code de certification) pour l'ajouter à sa collection numérique.

## Flux principal

1. L'utilisateur ouvre l'écran de scan.
2. La caméra s'active automatiquement.
3. Le QR code / code PSA est détecté.
4. L'app récupère les données de la carte via l'API PSA (nom du Pokémon, set, numéro, grade, numéro de certification, éventuellement visuel).
5. L'app affiche une fiche détaillée avec les infos PSA + les infos propres à l'app (collection, tags, notes…).

## Règles métier

- Si la carte est déjà dans la collection → afficher un dialogue « Cette carte PSA est déjà dans ta collection ».
- Si l'API PSA ne répond pas → afficher une erreur explicite et proposer de réessayer.
- Si le QR/code est illisible → afficher un message d'erreur et permettre de rescanner.
- Le scan + appel API PSA doivent s'effectuer en moins de 500 ms dans des conditions normales.

Ce fichier devient ta source de vérité, tant pour toi que pour ton agent IA.


3. L'IA comme "dev junior ultra rapide"... mais cadré

3.1. Ce que l'IA fait très bien

  • générer des classes, services, etc.
  • créer des widgets réutilisables
  • écrire des boilerplates fastidieux
  • refactorer du code
  • suggérer des patterns plus propres

3.2. Ce qu'elle fait mal sans contexte

  • gérer les règles métier
  • maintenir la cohérence globale
  • anticiper les edge cases
  • comprendre un flux complexe sans spec

D'où l'importance d'un bon fichier AGENTS.md, ou d'une spec claire accessible pour tes agents. Tu construis le cadre, l'IA construit le code.


4. Le rôle central des tests dans ce workflow

Pour transformer un agent IA en développeur fiable, les tests deviennent ton filet de sécurité.

4.1. Les trois étages des tests Flutter

🟦 Unit tests

Pour tester la logique métier :

import 'package:flutter_test/flutter_test.dart';
import 'package:myapp/domain/pokemon_service.dart';

void main() {
  group('PokemonService', () {
    test("ajout d'une carte PSA déjà présente", () {
      final service = PokemonService();

      service.addFromPsaCert('PSA-123');
      final result = service.addFromPsaCert('PSA-123');

      expect(result.isSuccess, false);
      expect(result.errorCode, 'already_exists');
    });
  });
}

🟨 Widget tests

Pour valider l'UI + interactions sans lancer l'app complète. Exemple : vérifier que l'écran de scan affiche bien l'aperçu de la carte PSA retournée par l'API.

import 'package:flutter_test/flutter_test.dart';
import 'package:flutter/material.dart';
import 'package:myapp/ui/scan_screen.dart';
import 'package:myapp/domain/pokemon_service.dart';

class FakePokemonService extends PokemonService {
  @override
  Future<PokemonCard> fetchFromPsa(String certId) async {
    return PokemonCard(
      id: 'PSA-123',
      name: 'Pikachu',
      setName: 'Base Set',
      grade: '10',
    );
  }
}

void main() {
  testWidgets('affiche la fiche PSA après scan réussi', (WidgetTester tester) async {
    await tester.pumpWidget(
      MaterialApp(
        home: ScanScreen(
          pokemonService: FakePokemonService(),
        ),
      ),
    );

    // On simule ici le résultat d'un scan réussi (par ex. via un callback).
    final state = tester.state<ScanScreenState>(find.byType(ScanScreen));
    await state.onScanResult('PSA-123');
    await tester.pumpAndSettle();

    expect(find.text('Pikachu'), findsOneWidget);
    expect(find.text('Base Set'), findsOneWidget);
    expect(find.text('PSA 10'), findsOneWidget);
  });
}

🟩 Integration tests

Pour simuler un vrai parcours utilisateur : ouvrir l'app, aller sur l'écran de scan, scanner une carte PSA, voir la fiche, et éventuellement prendre un screenshot exploitable dans une issue.

import 'package:flutter_test/flutter_test.dart';
import 'package:integration_test/integration_test.dart';
import 'package:myapp/main.dart' as app;
import 'dart:io';

void main() {
  IntegrationTestWidgetsFlutterBinding.ensureInitialized();

  testWidgets('parcours complet de scan PSA', (WidgetTester tester) async {
    app.main();
    await tester.pumpAndSettle();

    // Aller sur l'écran de scan
    await tester.tap(find.byKey(const Key('go-to-scan-button')));
    await tester.pumpAndSettle();

    // Ici tu peux mocker la couche caméra / scan pour renvoyer un certId PSA.
    // Par exemple via un FakeScanner ou un flag de debug.

    // Une fois le scan simulé, on attend le chargement de la fiche.
    await tester.pumpAndSettle(const Duration(seconds: 1));

    expect(find.text('Pikachu'), findsOneWidget);

    // Prendre un screenshot et le stocker dans un dossier lié à une issue
    final binding = IntegrationTestWidgetsFlutterBinding.instance;
    final bytes = await binding.takeScreenshot('scan_psa_flow');
    final dir = Directory('test_screenshots/issue-123');
    if (!dir.existsSync()) {
      dir.createSync(recursive: true);
    }
    final file = File('test_screenshots/issue-123/scan_psa_flow.png');
    await file.writeAsBytes(bytes);
  });
}

Ce pattern est super puissant : chaque bug identifié peut avoir son scénario d'intégration + son screenshot dans un dossier dédié (par ex. test_screenshots/issue-123/). C'est précieux pour documenter les régressions et faciliter la communication dans l'équipe (ou avec ton toi du futur).

4.2. Le cycle complet IA + tests

  1. Tu écris/complètes la spec.
  2. Tu la laisses digérer par ton agent IA.
  3. L'IA propose du code.
  4. Tu fais tourner les tests (unit, widget, intégration).
  5. Tout est vert → merge.
  6. Un test échoue → ajustement du code ou de la spec.

4.3. Schéma du workflow complet

On peut résumer ce workflow en une boucle simple :

Loading diagram...

L'idée importante : la doc et la spec ne sont pas un exercice à faire qu'une seule fois. Elles évoluent au même rythme que le code et les tests.

4.4. Mieux exploiter les screenshots dans le processus de test

Prendre un screenshot en fin de test d'intégration, ce n'est pas juste « pour la beauté du geste ». Tu peux en faire un vrai outil de travail :

  • 📌 Documentation de bug : quand tu ouvres une issue (GitHub, Jira...), tu peux rattacher le screenshot généré par le test (test_screenshots/issue-123/scan_psa_flow.png). On sait exactement à quoi ressemblait l'écran au moment où ça cassait.
  • 🧪 Régression visuelle "pauvre mais efficace" : sans mettre en place une usine à gaz de visual testing, tu peux déjà comparer les screenshots entre deux branches / deux versions. Une diff visuelle grossière peut déjà révéler des oublis (bouton qui disparaît, texte qui dépasse, etc.).
  • 🧭 Onboarding & story telling : un dossier test_screenshots bien rangé, c'est aussi une manière de montrer rapidement « à quoi ressemble » tel ou tel flow, sans lancer l'app. Pratique quand tu intègres un nouveau dev, un QA, ou que tu documentes pour toi‑même.
  • 🔁 Traçabilité : l'ID de l'issue dans le chemin (issue-123) crée un lien naturel entre spec → test → capture → ticket. Quand tu fermes le ticket, tu peux garder la capture comme "photo avant/après" dans la discussion.

Pour aller plus loin, tu peux même automatiser l'upload de ces screenshots comme artefacts de CI, ou les poster automatiquement en commentaire de PR pour des flows critiques.


5. Exemple concret sur une base Flutter

Voici un exemple de structure de tests + code générés dans un vrai projet Flutter :

lib/
  domain/
    pokemon_service.dart
  ui/
    scan_screen.dart
    pokemon_card.dart
  data/
    pokemon_repository.dart

test/
  unit/
    pokemon_service_test.dart
  widget/
    scan_screen_test.dart
  integration/
    scan_flow_test.dart

specs/
  scan_pokemon.md
  add_to_collection.md
  error_cases.md

Et côté CI :

flutter test
flutter test integration_test

Ce genre d'organisation rend la collaboration IA + dev extrêmement fluide.


6. Pourquoi cette méthode change tout

Plus rapide

L'IA fait le travail fastidieux. Tu te concentres sur la logique, le métier, l'UX.

Plus fiable

La spec + les tests transforment l'IA en outil sûr.

Plus maintenable

Refactorer le code devient un vrai plaisir quand tout est testé.

Plus aligné avec le métier

Le raisonnement part de la spec, pas de l'implémentation hasardeuse.


7. Mise à jour de la doc : fermer la boucle

Il manque souvent une étape dans nos workflows : revenir à la doc une fois le travail accompli.

À chaque fois que :

  • tu ajoutes une nouvelle règle métier,
  • tu corriges un bug,
  • tu modifies un flux,

...tu devrais mettre à jour :

  • la spec correspondante,
  • éventuellement le fichier de contexte (AGENTS.md, doc d'architecture),
  • la référence vers le test et le screenshot associés,

C'est ça qui transforme ta doc en documentation vivante, alignée avec le code. L'IA en profite (meilleur contexte), et toi aussi quand tu reviens sur le projet 6 mois plus tard.


8. Limites (soyons honnêtes)

  • Surchargé pour les petites features.
  • Une mauvaise spec = un mauvais résultat, même avec IA.
  • L'UI complexe nécessite encore de la finesse manuelle.
  • Demande une petite discipline (mais le gain en maintenabilité est significatif).

9. Pour aller plus loin : Spec Kit et les specs pilotées par l'IA

Si tu veux pousser la démarche encore plus loin, tu peux jeter un œil à Spec Kit, l'outil open source de GitHub pensé pour le spec-driven development :

  • tu écris d'abord une spec détaillée (le "quoi" et le "pourquoi"),
  • l'outil t'aide à en dériver un plan technique et une liste de tâches,
  • ensuite tu laisses ton agent IA générer le code à partir de ces artefacts,
  • et tu relies tout ça à tes tests existants.

L'idée est la même que celle qu'on vient de voir, mais formalisée dans un outil générique, pensé pour fonctionner avec plusieurs assistants IA. Même si Spec Kit cible plutôt l'écosystème web pour l'instant, la philosophie reste 100 % réutilisable dans un autre contexte :

  • commencer par des specs solides,
  • garder une séparation claire entre l'intention (docs) et l'implémentation (code),
  • utiliser l'IA comme un exécutant rapide, pas comme la source de vérité,
  • verrouiller le tout avec des tests automatisés.

Tu peux très bien imaginer un futur où :

  • Spec Kit (ou un équivalent) décrit tes features à haut niveau,
  • un agent IA génère la couche Flutter (UI + logique),
  • et tes tests Flutter viennent valider que l'implémentation colle bien à la spec.

Bref, si tu es lead dev ou que tu réfléchis à l'industrialisation de ton workflow avec l'IA, ça vaut le coup d'expérimenter ce genre d'outils, ne serait‑ce que pour voir comment ta manière de penser les specs évolue.


Conclusion

Le futur du dev en Flutter ne sera pas juste "coder plus vite avec l'IA". Ce sera :

coder avec intention + coder avec assistance + coder avec sûreté.

Un workflow où :

  • la spec dit ce qu'on veut,
  • l'IA propose comment le faire,
  • les tests garantissent que c'est bien fait.

Et toi, tu as déjà testé ce type de workflow en Flutter ? Je serais curieux de lire ton retour.


Liens utiles

Tags

  • flutter
  • mobile
  • tests
  • ia
  • spec-driven-development
  • workflow
  • retour-experience
  • architecture
  • best-practices

Cet article à été posté le