Test e Qualità del Codice in Flutter

Test e Qualità del Codice in Flutter

Test e Qualità del Codice in Flutter: Dalle Basi all’Automazione Continua

Guida pratica per sviluppatori con esempi di codice e workflow CI/CD

Introduzione

La qualità del codice in Flutter non è un optional: è la base per app performanti, mantenibili e scalabili. In questo articolo esploreremo un approccio strutturato ai test (unitari, widget, integrazione) e la loro automazione tramite CI/CD, con esempi concreti e best practice validate dalla community.

1. I Tre Pilastri dei Test in Flutter

1.1 Test Unitari: Verificare la logica pura

Quando usarli: Per funzioni isolate, classi di business logic, utility.
Best practice:

  • Testare un solo concetto per test
  • Usare setUp/tearDown per configurazione ripetibile
  • Mock delle dipendenze con mocktail

Esempio: Test di un Validatore di Email

import 'package:flutter_test/flutter_test.dart';
import 'package:my_app/validators.dart';

void main() {
  test('Email vuota dovrebbe restituire errore', () {
    expect(EmailValidator.validate(''), 'Email obbligatoria');
  });

  test('Email senza @ dovrebbe restituire errore', () {
    expect(EmailValidator.validate('email.example.com'), 'Email non valida');
  });

  test('Email valida dovrebbe restituire null', () {
    expect(EmailValidator.validate('test@example.com'), null);
  });
}

1.2 Widget Test: Verifica dell’UI isolata

Quando usarli: Per componenti UI singoli senza dipendenze esterne.
Best practice:

  • Usare WidgetTester per interazioni simulate
  • Testare stati diversi (loading, error, dati)
  • Mockare gli strati di business logic

Esempio: Test di un Pulsante con Stato

testWidgets('LoginButton dovrebbe mostrare spinner durante il loading', (tester) async {
  await tester.pumpWidget(
    MaterialApp(home: LoginButton(isLoading: true)),
  );

  expect(find.byType(CircularProgressIndicator), findsOneWidget);
  expect(find.text('Accedi'), findsNothing);
});

1.3 Test di Integrazione: Flussi completi

Quando usarli: Per scenari utente end-to-end tra più componenti.
Best practice:

  • Testare percorsi utente reali (es: login > dashboard)
  • Usare IntegrationTestWidgetsFlutterBinding
  • Simulare input utente complessi

Esempio: Test del Flusso di Login

import 'package:integration_test/integration_test.dart';

void main() {
  IntegrationTestWidgetsFlutterBinding.ensureInitialized();

  testWidgets('Completa flusso di login', (tester) async {
    await tester.pumpWidget(MyApp());

    await tester.enterText(find.byKey(Key('email-field')), 'user@example.com');
    await tester.enterText(find.byKey(Key('password-field')), 'password123');
    await tester.tap(find.byKey(Key('login-button')));

    await tester.pumpAndSettle();

    expect(find.text('Benvenuto, User!'), findsOneWidget);
  });
}

2. Automazione CI/CD: Build, Test e Deploy Automatici

2.1 Configurazione Base per GitHub Actions

Crea .github/workflows/flutter-ci.yml:

name: Flutter CI

on: [push, pull_request]

jobs:
  build-test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Setup Flutter
        uses: subosito/flutter-action@v2
        with:
          flutter-version: '3.22.0'

      - name: Install dependencies
        run: flutter pub get

      - name: Run Unit Tests
        run: flutter test

      - name: Run Widget Tests
        run: flutter test --update-goldens

      - name: Run Integration Tests
        run: flutter test integration_test --device-id=chrome

      - name: Build APK
        if: github.ref == 'refs/heads/main'
        run: flutter build apk --release

2.2 Configurazione Avanzata per GitLab CI/CD

Crea .gitlab-ci.yml:

image: cirrusci/flutter:3.22.0

stages:
  - test
  - build

unit_test:
  stage: test
  script:
    - flutter pub get
    - flutter test

widget_test:
  stage: test
  script:
    - flutter test --update-goldens

integration_test:
  stage: test
  script:
    - flutter emulators --launch emulator
    - flutter test integration_test

build_apk:
  stage: build
  only:
    - main
  script:
    - flutter build apk --release
  artifacts:
    paths:
      - build/app/outputs/apk/release/app-release.apk

Ottimizzazioni CI/CD

  1. Caching delle dipendenze:
   # GitHub Actions
   - name: Cache Flutter dependencies
     uses: actions/cache@v3
     with:
       path: /opt/hostedtoolcache/flutter
       key: flutter-deps-${{ hashFiles('pubspec.lock') }}
  1. Parallelizzazione dei test:
   # GitLab CI
   unit_test_ios:
     extends: .test_template
     variables:
       TARGET_PLATFORM: ios
  1. Quality Gate:
   - name: Run Code Metrics
     run: |
       flutter pub run dart_code_metrics:metrics analyze lib
       flutter pub run dart_code_metrics:metrics check-unused-code lib

3. Integrazione nel Flusso di Sviluppo

Workflow Consigliato

  1. Pre-commit Hook:
   # .git/hooks/pre-commit
   flutter test && dart format --set-exit-if-changed .
  1. Branch Protection Rules:
  • Obbligo di superamento CI per merge
  • Code review obbligatoria
  • Controlli di formattazione automatici
  1. Pipeline Strategica:
  

  

ConclusioniTest e Qualità del Codice in Flutter

Implementare un solido sistema di test + CI/CD in Flutter:

  1. Riduce i bug in produzione del 40-70% (fonte: Google Engineering)
  2. Accelera il time-to-market con deploy automatizzati
  3. Migliora la manutenibilità del codice

Nota : Questa configurazione è stata testata con Flutter 3.22 (stable). Per progetti complessi, considerare l’uso di Melos per monorepo e test paralleli avanzati.

(fonte) (fonte) (fonte)

Innovaformazione, scuola informatica specialistica promuove la cultura dello sviluppo con Flutter in maniera consapevole e moderna. Accompagniamo le aziende IT nella formazione del team di sviluppo con i nostri corsi. Fra questi trovate il Corso Flutter.

INFO: info@innovaformazione.net – Tel. 3471012275 (Dario Carrassi)

Vuoi essere ricontattato? Lasciaci il tuo numero telefonico e la tua email, ti richiameremo nelle 24h:

    Ti potrebbe interessare

    Articoli correlati