Saltar al contenido principal

Una introducción a las pruebas de widgets

Aprende más sobre las pruebas de widgets en Flutter.

En la receta de introducción a las pruebas unitarias, aprendiste a probar clases Dart usando el paquete test. Para probar clases de widgets, necesitas algunas herramientas adicionales proporcionadas por el paquete flutter_test, que viene con el SDK de Flutter.

El paquete flutter_test proporciona las siguientes herramientas para probar widgets:

  • El WidgetTester permite construir e interactuar con widgets en un entorno de pruebas.
  • La función testWidgets() crea automáticamente un nuevo WidgetTester para cada caso de prueba y se utiliza en lugar de la función test() normal.
  • Las clases Finder permiten buscar widgets en el entorno de pruebas.
  • Las constantes Matcher específicas de widgets ayudan a verificar si un Finder localiza un widget o múltiples widgets en el entorno de pruebas.

Si esto suena abrumador, no te preocupes. Aprende cómo encajan todas estas piezas a lo largo de esta receta, la cual utiliza los siguientes pasos:

  1. Añade la dependencia flutter_test.
  2. Crea un widget para probar.
  3. Crea una prueba testWidgets.
  4. Construye el widget usando el WidgetTester.
  5. Busca el widget usando un Finder.
  6. Verifica el widget usando un Matcher.

1. Añade la dependencia flutter_test

#

Antes de escribir pruebas, incluye la dependencia flutter_test en la sección dev_dependencies del archivo pubspec.yaml. Si creas un nuevo proyecto Flutter con las herramientas de línea de comandos o un editor de código, esta dependencia ya debería estar en su lugar.

yaml
dev_dependencies:
  flutter_test:
    sdk: flutter

2. Crea un widget para probar

#

A continuación, crea un widget para probar. Para esta receta, crea un widget que muestre un title y un message.

dart
class MyWidget extends StatelessWidget {
  const MyWidget({super.key, required this.title, required this.message});

  final String title;
  final String message;

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      home: Scaffold(
        appBar: AppBar(title: Text(title)),
        body: Center(child: Text(message)),
      ),
    );
  }
}

3. Crea una prueba testWidgets

#

Con un widget para probar, comienza escribiendo tu primera prueba. Utiliza la función testWidgets() proporcionada por el paquete flutter_test para definir una prueba. La función testWidgets te permite definir una prueba de widget y crea un WidgetTester con el cual trabajar.

Esta prueba verifica que MyWidget muestre un título y un mensaje dados. Está titulada en consecuencia y se completará en la siguiente sección.

dart
void main() {
  // Define a test. The TestWidgets function also provides a WidgetTester
  // to work with. The WidgetTester allows you to build and interact
  // with widgets in the test environment.
  testWidgets('MyWidget has a title and message', (tester) async {
    // Test code goes here.
  });
}

4. Construye el widget usando el WidgetTester

#

A continuación, construye MyWidget dentro del entorno de pruebas utilizando el pumpWidget() método proporcionado por WidgetTester. El método pumpWidget construye y renderiza el widget proporcionado.

Crea una instancia de MyWidget que muestre "T" como título y "M" como mensaje.

dart
void main() {
  testWidgets('MyWidget has a title and message', (tester) async {
    // Create the widget by telling the tester to build it.
    await tester.pumpWidget(const MyWidget(title: 'T', message: 'M'));
  });
}

Notas sobre los métodos pump()

#

Después de la llamada inicial a pumpWidget(), el WidgetTester ofrece formas adicionales de reconstruir el mismo widget. Esto es útil si estás trabajando con un StatefulWidget o animaciones.

Por ejemplo, al tocar un botón se llama a setState(), pero Flutter no reconstruirá automáticamente tu widget en el entorno de pruebas. Utiliza uno de los siguientes métodos para pedirle a Flutter que reconstruya el widget.

tester.pump(Duration duration)

Programa un fotograma (frame) y activa una reconstrucción del widget. Si se especifica una duración (Duration), avanza el reloj esa cantidad y programa un fotograma. No programa múltiples fotogramas incluso si la duración es mayor que la de un solo fotograma.

tester.pumpAndSettle()

Llama repetidamente a pump() con la duración dada hasta que ya no haya fotogramas programados. Esto, esencialmente, espera a que se completen todas las animaciones.

Estos métodos proporcionan un control detallado sobre el ciclo de vida de construcción, lo cual es particularmente útil durante las pruebas.

5. Busca nuestro widget usando un Finder

#

Con un widget en el entorno de pruebas, busca a través del árbol de widgets los widgets title y message Text usando un Finder. Esto permite verificar que los widgets se estén mostrando correctamente.

Para este propósito, utiliza el método de nivel superior find() proporcionado por el paquete flutter_test para crear los Finders. Dado que sabes que estás buscando widgets Text, utiliza el find.text() método.

Para más información sobre las clases Finder, consulta la receta Buscar widgets en una prueba de widget.

dart
void main() {
  testWidgets('MyWidget has a title and message', (tester) async {
    await tester.pumpWidget(const MyWidget(title: 'T', message: 'M'));

    // Create the Finders.
    final titleFinder = find.text('T');
    final messageFinder = find.text('M');
  });
}

6. Verifica el widget usando un Matcher

#

Finalmente, verifica que los widgets Text de título y mensaje aparezcan en pantalla usando las constantes Matcher proporcionadas por flutter_test. Las clases Matcher son una parte central del paquete test, y proporcionan una forma común de verificar que un valor dado cumpla con las expectativas.

Asegúrate de que los widgets aparezcan en pantalla exactamente una vez. Para este propósito, utiliza el findsOneWidget Matcher.

dart
void main() {
  testWidgets('MyWidget has a title and message', (tester) async {
    await tester.pumpWidget(const MyWidget(title: 'T', message: 'M'));
    final titleFinder = find.text('T');
    final messageFinder = find.text('M');

    // Use the `findsOneWidget` matcher provided by flutter_test to verify
    // that the Text widgets appear exactly once in the widget tree.
    expect(titleFinder, findsOneWidget);
    expect(messageFinder, findsOneWidget);
  });
}

Matchers adicionales

#

Además de findsOneWidget, flutter_test proporciona matchers adicionales para casos comunes.

findsNothing

Verifica que no se encuentren widgets.

findsWidgets

Verifica que se encuentren uno o más widgets.

findsNWidgets

Verifica que se encuentre un número específico de widgets.

matchesGoldenFile

Verifica que el renderizado de un widget coincida con una imagen de mapa de bits particular (pruebas de "archivo golden" o "golden file").

Ejemplo completo

#
dart
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';

void main() {
  // Define a test. The TestWidgets function also provides a WidgetTester
  // to work with. The WidgetTester allows building and interacting
  // with widgets in the test environment.
  testWidgets('MyWidget has a title and message', (tester) async {
    // Create the widget by telling the tester to build it.
    await tester.pumpWidget(const MyWidget(title: 'T', message: 'M'));

    // Create the Finders.
    final titleFinder = find.text('T');
    final messageFinder = find.text('M');

    // Use the `findsOneWidget` matcher provided by flutter_test to
    // verify that the Text widgets appear exactly once in the widget tree.
    expect(titleFinder, findsOneWidget);
    expect(messageFinder, findsOneWidget);
  });
}

class MyWidget extends StatelessWidget {
  const MyWidget({super.key, required this.title, required this.message});

  final String title;
  final String message;

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      home: Scaffold(
        appBar: AppBar(title: Text(title)),
        body: Center(child: Text(message)),
      ),
    );
  }
}