Cómo probar una app de Flutter

Flutter es el kit de herramientas de IU de Google diseñado para crear aplicaciones atractivas compiladas de forma nativa que funcionen en dispositivos móviles, la Web y computadoras de escritorio a partir de una base de código única.

En este codelab, compilarás y probarás una app de Flutter simple. La app usará el paquete Provider para administrar el estado.

Qué aprenderás

  • Cómo crear pruebas de widgets con el marco de trabajo de prueba del widget
  • Cómo crear una prueba de integración para probar la IU y el rendimiento de la app con el paquete integration_test
  • Cómo probar clases de datos (proveedores) con la ayuda de las pruebas de unidades

Qué compilarás

En este codelab, comenzarás a compilar una aplicación simple con una lista de elementos. Te proporcionamos el código fuente para que puedas comenzar directamente con las pruebas. La aplicación admite las siguientes operaciones:

  • Cómo agregar los elementos a favoritos
  • Cómo ver la lista de favoritos
  • Cómo quitar elementos de la lista de favoritos

Una vez que la app esté completa, escribirás las siguientes pruebas:

  • Pruebas de unidades para validar las operaciones de agregar y quitar
  • Pruebas de widgets para la página principal y de favoritos
  • Pruebas de IU y rendimiento para toda la app con pruebas de integración

GIF de la app que se ejecuta en Android

¿Qué te gustaría aprender de este codelab?

Desconozco el tema y me gustaría obtener una buena descripción general. Tengo algunos conocimientos sobre este tema, pero me gustaría repasarlos. Estoy buscando un código de ejemplo para usar en mi proyecto. Estoy buscando una explicación sobre un tema específico.

Para completar este lab, necesitas dos software: el SDK de Flutter y un editor.

Puedes ejecutar este codelab con cualquiera de los siguientes dispositivos:

  • Un dispositivo físico (Android o iOS) conectado a tu computadora y configurado en modo de desarrollador
  • El simulador de iOS (requiere instalar herramientas de Xcode)
  • Android Emulator (requiere configuración en Android Studio)

Cómo crear una app de Flutter nueva y actualizar las dependencias

Este codelab se enfoca en la prueba de una app para dispositivos móviles de Flutter. Crearás rápidamente la app que deseas probar con los archivos fuente que copias y pegas. El resto del codelab se enfoca en aprender diferentes tipos de pruebas.

b2f84ff91b0e1396.pngCrea una app de Flutter simple a partir de una plantilla siguiendo las instrucciones en Cómo comenzar a crear tu primera app de Flutter. Asigna el nombre testing_app al proyecto (en lugar de myapp). Modificarás esta app inicial para crear la app terminada.

b2f84ff91b0e1396.pngEn tu IDE o editor, abre el archivo pubspec.yaml. Agrega las siguientes dependencias marcadas como new y, luego, guarda el archivo. (Puedes borrar los comentarios para que el archivo sea más legible).

pubspec.yaml

dependencies:
  flutter:
    sdk: flutter
  cupertino_icons: ^0.1.3
  provider: ^4.1.3            # new

dev_dependencies:
  flutter_test:
    sdk: flutter
  integration_test: ^1.0.1    # new
  test: ^1.14.4               # new
  1. Haz clic en el botón Pub get en tu IDE o, en la línea de comandos, ejecuta flutter pub get desde la parte superior del proyecto.

Si se produce un error, asegúrate de que la sangría de tu bloque dependencies sea exactamente la misma que se mostró antes, con espacios (no tabulaciones). Los archivos YAML distinguen espacios en blanco.

Luego, compilarás la app para que puedas probarla. La app contiene los siguientes archivos:

  • lib/main.dart: Es el archivo principal donde se inicia la app.
  • lib/screens/home.dart: Crea una lista de elementos.
  • lib/screens/favorites.dart: Crea el diseño para la lista de favoritos.
  • lib/models/favorites.dart: Crea la clase del modelo para la lista de favoritos.

Reemplaza el contenido de lib/main.dart

b2f84ff91b0e1396.pngReemplaza el contenido de lib/main.dart con lo siguiente:

lib/main.dart

import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:testing_app/models/favorites.dart';
import 'package:testing_app/screens/favorites.dart';
import 'package:testing_app/screens/home.dart';

void main() {
  runApp(TestingApp());
}

class TestingApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return ChangeNotifierProvider<Favorites>(
      create: (context) => Favorites(),
      child: MaterialApp(
        title: 'Testing Sample',
        theme: ThemeData(
          primarySwatch: Colors.blue,
          visualDensity: VisualDensity.adaptivePlatformDensity,
        ),
        routes: {
          HomePage.routeName: (context) => HomePage(),
          FavoritesPage.routeName: (context) => FavoritesPage(),
        },
        initialRoute: HomePage.routeName,
      ),
    );
  }
}

Agrega la página principal a lib/screens/home.dart

b2f84ff91b0e1396.pngCrea un directorio nuevo, screens, en el directorio lib, y en ese directorio que acabas de crear, crea un archivo nuevo llamado home.dart. En lib/screens/home.dart, agrega el siguiente código.

lib/screens/home.dart

import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:testing_app/models/favorites.dart';
import 'package:testing_app/screens/favorites.dart';

class HomePage extends StatelessWidget {
  static String routeName = '/';

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Testing Sample'),
        actions: <Widget>[
          TextButton.icon(
            style: TextButton.styleFrom(primary: Colors.white),
            onPressed: () {
              Navigator.pushNamed(context, FavoritesPage.routeName);
            },
            icon: Icon(Icons.favorite_border),
            label: Text('Favorites'),
          ),
        ],
      ),
      body: ListView.builder(
        itemCount: 100,
        cacheExtent: 20.0,
        padding: const EdgeInsets.symmetric(vertical: 16),
        itemBuilder: (context, index) => ItemTile(index),
      ),
    );
  }
}

class ItemTile extends StatelessWidget {
  final int itemNo;

  const ItemTile(
    this.itemNo,
  );

  @override
  Widget build(BuildContext context) {
    var favoritesList = Provider.of<Favorites>(context);

    return Padding(
      padding: const EdgeInsets.all(8.0),
      child: ListTile(
        leading: CircleAvatar(
          backgroundColor: Colors.primaries[itemNo % Colors.primaries.length],
        ),
        title: Text(
          'Item $itemNo',
          key: Key('text_$itemNo'),
        ),
        trailing: IconButton(
          key: Key('icon_$itemNo'),
          icon: favoritesList.items.contains(itemNo)
              ? Icon(Icons.favorite)
              : Icon(Icons.favorite_border),
          onPressed: () {
            !favoritesList.items.contains(itemNo)
                ? favoritesList.add(itemNo)
                : favoritesList.remove(itemNo);
            ScaffoldMessenger.of(context).showSnackBar(
              SnackBar(
                content: Text(favoritesList.items.contains(itemNo)
                    ? 'Added to favorites.'
                    : 'Removed from favorites.'),
                duration: Duration(seconds: 1),
              ),
            );
          },
        ),
      ),
    );
  }
}

Agrega la página Favoritos a lib/screens/favorites.dart

b2f84ff91b0e1396.pngEn el directorio lib/screens, crea otro archivo nuevo llamado favorites.dart. En ese archivo, agrega el siguiente código:

lib/screens/favorites.dart

import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:testing_app/models/favorites.dart';

class FavoritesPage extends StatelessWidget {
  static String routeName = '/favorites_page';

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Favorites'),
      ),
      body: Consumer<Favorites>(
        builder: (context, value, child) => ListView.builder(
          itemCount: value.items.length,
          padding: const EdgeInsets.symmetric(vertical: 16),
          itemBuilder: (context, index) => FavoriteItemTile(value.items[index]),
        ),
      ),
    );
  }
}

class FavoriteItemTile extends StatelessWidget {
  final int itemNo;

  const FavoriteItemTile(
    this.itemNo,
  );

  @override
  Widget build(BuildContext context) {
    return Padding(
      padding: const EdgeInsets.all(8.0),
      child: ListTile(
        leading: CircleAvatar(
          backgroundColor: Colors.primaries[itemNo % Colors.primaries.length],
        ),
        title: Text(
          'Item $itemNo',
          key: Key('favorites_text_$itemNo'),
        ),
        trailing: IconButton(
          key: Key('remove_icon_$itemNo'),
          icon: Icon(Icons.close),
          onPressed: () {
            Provider.of<Favorites>(context, listen: false).remove(itemNo);
            ScaffoldMessenger.of(context).showSnackBar(
              SnackBar(
                content: Text('Removed from favorites.'),
                duration: Duration(seconds: 1),
              ),
            );
          },
        ),
      ),
    );
  }
}

Por último, crea el modelo Favorites en lib/models/favorites.dart

b2f84ff91b0e1396.pngCrea un directorio nuevo, models y, en ese directorio, crea un archivo nuevo llamado favorites.dart. En ese archivo, agrega el siguiente código:

lib/models/favorites.dart

import 'package:flutter/material.dart';

/// The [Favorites] class holds a list of favorite items saved by the user.
class Favorites extends ChangeNotifier {
  final List<int> _favoriteItems = [];

  List<int> get items => _favoriteItems;

  void add(int itemNo) {
    _favoriteItems.add(itemNo);
    notifyListeners();
  }

  void remove(int itemNo) {
    _favoriteItems.remove(itemNo);
    notifyListeners();
  }
}

La app ahora está completa, pero no probada.

b2f84ff91b0e1396.pngPara ejecutar la app, haz clic en el ícono Ejecutar 6869d41b089cc745.png en el editor. La primera vez que ejecutas una app, puede tardar un poco. La app es más rápida en los pasos posteriores. Debería verse como la siguiente captura de pantalla:

be938199b599b605.png

La app muestra una lista de elementos. Presiona el ícono con forma de corazón en cualquier fila para llenar el corazón y agregar el elemento a la lista de favoritos. El botón Favoritos de AppBar te lleva a una segunda pantalla que contiene la lista de favoritos.

La app ya está lista para las pruebas. Comenzarás a probarla desde el siguiente paso.

Comenzarás con la prueba de unidades del modelo favorites. ¿Qué es una prueba de unidades? Una prueba de unidades verifica que cada unidad de software individual (a menudo, una función) realice correctamente la tarea deseada.

Todos los archivos de prueba de una app de Flutter (excepto las pruebas de integración) se colocan en el directorio test.

Quita test/widget_test.dart

b2f84ff91b0e1396.pngAntes de comenzar la prueba, borra el archivo widget_test.dart. Agregarás tus propios archivos de prueba.

Cómo crear un nuevo archivo de prueba

Primero, probarás el método add() en el modelo Favorites para verificar que se agregue un nuevo elemento a la lista y que la lista refleje el cambio. Por convención, la estructura de directorios del directorio test imita la del directorio lib y los archivos Dart tienen el mismo nombre, pero con _test.

b2f84ff91b0e1396.pngCrea un directorio models en el directorio test. En este directorio nuevo, crea un archivo favourites_test.dart con el siguiente contenido:

test/models/favorites_test.dart

import 'package:test/test.dart';
import 'package:testing_app/models/favorites.dart';

void main() {
  group('App Provider Tests', () {
    var favorites = Favorites();

    test('A new item should be added', () {
      var number = 35;
      favorites.add(number);
      expect(favorites.items.contains(number), true);
    });
  });
}

El marco de trabajo de prueba de Flutter te permite vincular pruebas similares relacionadas entre sí en un grupo. Puede haber varios grupos en un solo archivo de prueba destinado a probar diferentes partes del archivo correspondiente en el directorio /lib.

El método test() usa dos parámetros posicionales: el description de la prueba y el callback donde escribes la prueba.

b2f84ff91b0e1396.pngPrueba quitar un elemento de la lista. Copia y pega la siguiente prueba en el mismo grupo de prueba. Agrega el siguiente código al archivo de prueba:

test/models/favorites_test.dart

test('An item should be removed', () {
  var number = 45;
  favorites.add(number);
  expect(favorites.items.contains(number), true);
  favorites.remove(number);
  expect(favorites.items.contains(number), false);
});

Ejecuta la prueba

b2f84ff91b0e1396.pngSi tu app se está ejecutando en tu emulador o dispositivo, ciérrala antes de continuar.

b2f84ff91b0e1396.pngEn la línea de comandos, navega al directorio raíz del proyecto y, luego, ingresa el siguiente comando:

$ flutter test test/models/favorites_test.dart

Si todo funciona, deberías ver un mensaje similar al siguiente:

00:06 +2: All tests passed!

El archivo de prueba completo: test/models/favorites_test.dart.

Si quieres obtener más información sobre la prueba de unidades, consulta Introducción a la prueba de unidades.

En este paso, realizarás pruebas de widgets. Las pruebas de widgets son exclusivas de Flutter, donde puedes probar cada uno de los widgets individuales que elijas. En este paso, se prueban las pantallas (HomePage y FavoritesPage) de manera individual.

Las pruebas de widgets usan la función testWidget() en lugar de test(). También usan dos parámetros: description, y callback. Sin embargo, en este caso, la devolución de llamada toma un objeto WidgetTester como argumento.

Las pruebas de widgets usan TestFlutterWidgetsBinding, una clase que proporciona los mismos recursos a tus widgets que tendrían en una app en ejecución (información sobre el tamaño de la pantalla, la capacidad de programar animaciones, etc.), pero sin la app real. En cambio, se usa un entorno virtual para ejecutar el widget, medirlo, etc., y luego probar los resultados. Aquí, pumpWidget inicia el proceso indicando al marco de trabajo que active y mida un widget en particular como lo haría en una aplicación completa.

El marco de trabajo de prueba del widget proporciona detectores para encontrar widgets (por ejemplo, text(), byType() y byIcon()) y también busca comparadores para verificar los resultados.

Comienza por probar el widget HomePage.

Cómo crear un nuevo archivo de prueba

La primera prueba verifica si el desplazamiento de HomePage funciona correctamente.

b2f84ff91b0e1396.pngCrea un archivo nuevo en el directorio test y asígnale el nombre home_test.dart. En el archivo recién creado, agrega el siguiente código:

test/home_test.dart

import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:provider/provider.dart';
import 'package:testing_app/models/favorites.dart';
import 'package:testing_app/screens/home.dart';

Widget createHomeScreen() => ChangeNotifierProvider<Favorites>(
      create: (context) => Favorites(),
      child: MaterialApp(
        home: HomePage(),
      ),
    );

void main() {
  group('Home Page Widget Tests', () {
    testWidgets('Testing Scrolling', (tester) async {
      await tester.pumpWidget(createHomeScreen());
      expect(find.text('Item 0'), findsOneWidget);
      await tester.fling(find.byType(ListView), Offset(0, -200), 3000);
      await tester.pumpAndSettle();
      expect(find.text('Item 0'), findsNothing);
    });
  });
}

La función createHomeScreen() se usa para crear una app que cargue el widget que se probará en una app de Material, en un ChangeNotifierProvider. El widget de Página principal necesita que ambos widgets estén presentes antes en el árbol de widgets para que puedan heredarlos y acceder a los datos que ofrecen. Esta función se pasa como parámetro a la función pumpWidget().

A continuación, prueba si el marco de trabajo puede encontrar un elemento ListView procesado en la pantalla.

b2f84ff91b0e1396.pngAgrega el siguiente fragmento de código a home_test.dart:

test/home_test.dart

group('Home Page Widget Tests', () {

  // BEGINNING OF NEW CONTENT
  testWidgets('Testing if ListView shows up', (tester) async {
    await tester.pumpWidget(createHomeScreen());
    expect(find.byType(ListView), findsOneWidget);
  });
  // END OF NEW CONTENT

  testWidgets('Testing Scrolling', (tester) async {
    await tester.pumpWidget(createHomeScreen());
    expect(find.text('Item 0'), findsOneWidget);
    await tester.fling(find.byType(ListView), Offset(0, -200), 3000);
    await tester.pumpAndSettle();
    expect(find.text('Item 0'), findsNothing);
  });
});

Ejecuta la prueba

Puedes ejecutar pruebas de widget del mismo modo que las pruebas de unidades, pero el uso de un dispositivo o un emulador te permite ver la prueba en ejecución. También te brinda la capacidad de usar el reinicio en caliente.

b2f84ff91b0e1396.pngConecta el dispositivo o inicia tu emulador.

b2f84ff91b0e1396.pngDesde la línea de comandos, navega al directorio raíz del proyecto y, luego, ingresa el siguiente comando:

$ flutter run test/home_test.dart

Si todo funciona, deberías ver un resultado similar al siguiente:

Launching test/home_test.dart on Mi A3 in debug mode...
Running Gradle task 'assembleDebug'...
Running Gradle task 'assembleDebug'... Done                        62.7s
✓ Built build/app/outputs/flutter-apk/app-debug.apk.
Installing build/app/outputs/flutter-apk/app.apk...                 5.8s
Waiting for Mi A3 to report its views...                            16ms
I/flutter ( 1616): 00:00 +0: Home Page Widget Tests Testing if ListView shows up
Syncing files to device Mi A3...
I/flutter ( 1616): 00:02 +1: Home Page Widget Tests Testing Scrolling
Syncing files to device Mi A3...                                                 4,008ms (!)

Flutter run key commands.
r Hot reload. 🔥🔥🔥
R Hot restart.
h Repeat this help message.
d Detach (terminate "flutter run" but leave application running).
c Clear the screen
q Quit (terminate the application on the device).
An Observatory debugger and profiler on Mi A3 is available at:
http://127.0.0.1:40433/KOsGesHSxR8=/
I/flutter ( 1616): 00:00 +0: Home Page Widget Tests Testing if ListView shows up
I/flutter ( 1616): 00:02 +1: Home Page Widget Tests Testing Scrolling
I/flutter ( 1616): 00:09 +3: All tests passed!

A continuación, realiza los cambios en el archivo de prueba y, luego, ingresa Shift + R para reiniciar la app en tiempo real y volver a ejecutar todas las pruebas.

b2f84ff91b0e1396.pngAgrega más pruebas al grupo que prueba los widgets de la página principal. Copia esta prueba en tu archivo:

test/home_test.dart

testWidgets('Testing IconButtons', (tester) async {
  await tester.pumpWidget(createHomeScreen());
  expect(find.byIcon(Icons.favorite), findsNothing);
  await tester.tap(find.byIcon(Icons.favorite_border).first);
  await tester.pumpAndSettle(Duration(seconds: 1));
  expect(find.text('Added to favorites.'), findsOneWidget);
  expect(find.byIcon(Icons.favorite), findsWidgets);
  await tester.tap(find.byIcon(Icons.favorite).first);
  await tester.pumpAndSettle(Duration(seconds: 1));
  expect(find.text('Removed from favorites.'), findsOneWidget);
  expect(find.byIcon(Icons.favorite), findsNothing);
});

Esta prueba verifica que, al presionar IconButton, cambie de Icons.favorite_border (un corazón abierto) a Icons.favorite (un corazón relleno) y, luego, vuelva a Icons.favorite_border cuando se presiona nuevamente.

b2f84ff91b0e1396.pngIngresa Shift + R. Esta acción reinicia la app en caliente y vuelve a ejecutar todas las pruebas.

El archivo de prueba completo: test/home_test.dart.

b2f84ff91b0e1396.pngUsa el mismo proceso para probar FavoritesPage con el siguiente código. Sigue los mismos pasos y ejecútalo.

test/favorites_test.dart

import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:provider/provider.dart';
import 'package:testing_app/models/favorites.dart';
import 'package:testing_app/screens/favorites.dart';

Favorites favoritesList;

Widget createFavoritesScreen() => ChangeNotifierProvider<Favorites>(
      create: (context) {
        favoritesList = Favorites();
        return favoritesList;
      },
      child: MaterialApp(
        home: FavoritesPage(),
      ),
    );

void addItems() {
  for (var i = 0; i < 10; i += 2) {
    favoritesList.add(i);
  }
}

void main() {
  group('Favorites Page Widget Tests', () {
    testWidgets('Test if ListView shows up', (tester) async {
      await tester.pumpWidget(createFavoritesScreen());
      addItems();
      await tester.pumpAndSettle();
      expect(find.byType(ListView), findsOneWidget);
    });

    testWidgets('Testing Remove Button', (tester) async {
      await tester.pumpWidget(createFavoritesScreen());
      addItems();
      await tester.pumpAndSettle();
      var totalItems = tester.widgetList(find.byIcon(Icons.close)).length;
      await tester.tap(find.byIcon(Icons.close).first);
      await tester.pumpAndSettle();
      expect(tester.widgetList(find.byIcon(Icons.close)).length,
          lessThan(totalItems));
      expect(find.text('Removed from favorites.'), findsOneWidget);
    });
  });
}

Esta prueba verifica si desaparece un elemento cuando se presiona el botón para cerrar (quitar).

Para obtener más información sobre la prueba de widgets, consulta lo siguiente:

Las pruebas de integración se usan para probar en conjunto las piezas individuales de una app. El paquete integration_test se usa para realizar pruebas de integración en Flutter. Esta es la versión de Flutter de Selenium WebDriver (web genérica), Protractor (Angular), Espresso (Android) o Earl Gray (iOS). El paquete usa internamente flutter_driver para impulsar la prueba en un dispositivo.

Cómo instrumentar la app

Para escribir una prueba de integración, primero debes instrumentar la app, lo que significa configurar la app para que el controlador pueda acceder a su GUI y sus funciones con el fin de crear y ejecutar una prueba automatizada. Las pruebas de integración se colocan en un directorio llamado integration_test. En este paso, agregarás los siguientes archivos para las pruebas de integración:

  • integration_test/driver.dart: Instrumenta la app.
  • integration_test/app_test.dart: Ejecuta las pruebas reales en la app.

b2f84ff91b0e1396.pngCrea un directorio llamado integration_test en el directorio raíz del proyecto. En ese directorio recién creado, crea un archivo driver.dart y agrega el siguiente código:

integration_test/driver.dart

import 'package:integration_test/integration_test_driver.dart';

Future<void> main() => integrationDriver();

Este código habilita el controlador de pruebas de integración y espera a que la prueba se ejecute. Los datos de respuesta se almacenan en un archivo llamado integration_response_data.json después de ejecutadas las pruebas.

Escribe la prueba

b2f84ff91b0e1396.pngCrea un archivo nuevo y asígnale el nombre app_test.dart.

integration_test/app_test.dart

import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:integration_test/integration_test.dart';
import 'package:testing_app/main.dart';

void main() {
  group('Testing App Performance Tests', () {
    final binding = IntegrationTestWidgetsFlutterBinding.ensureInitialized()
        as IntegrationTestWidgetsFlutterBinding;

    binding.framePolicy = LiveTestWidgetsFlutterBindingFramePolicy.fullyLive;
  });
}

La función ensureInitialized() verifica si se inicializa el controlador de prueba de integración o no, y lo reinicia si es necesario. Cuando framePolicy se configura como fullyLive de la enumeración LiveTestWidgetsFlutterBindingFramePolicy, es más adecuado para probar situaciones animadas.

A continuación, prueba el rendimiento de desplazamiento de la app y regístralo con la función watchPerformance().

b2f84ff91b0e1396.pngPega el siguiente código en el grupo de prueba que acabas de crear:

integration_test/app_test.dart

testWidgets('Scrolling test', (tester) async {
  await tester.pumpWidget(TestingApp());

  final listFinder = find.byType(ListView);

  await binding.watchPerformance(() async {
    await tester.fling(listFinder, Offset(0, -500), 10000);
    await tester.pumpAndSettle();

    await tester.fling(listFinder, Offset(0, 500), 10000);
    await tester.pumpAndSettle();
  }, reportKey: 'scrolling_summary');
});

Esta prueba se desplaza por la lista de elementos rápidamente y luego se desplaza hacia arriba. La función watchPerformance() registra las acciones y genera un resumen del cronograma que luego se envía como datos de respuesta al controlador de pruebas en el archivo driver.dart.

A continuación, prueba las operaciones add y remove.

b2f84ff91b0e1396.pngPega la siguiente prueba en el mismo grupo:

integration_test/app_test.dart

testWidgets('Favorites operations test', (tester) async {
  await tester.pumpWidget(TestingApp());

  final iconKeys = [
    'icon_0',
    'icon_1',
    'icon_2',
  ];

  for (var icon in iconKeys) {
    await tester.tap(find.byKey(ValueKey(icon)));
    await tester.pumpAndSettle(Duration(seconds: 1));

    expect(find.text('Added to favorites.'), findsOneWidget);
  }

  await tester.tap(find.text('Favorites'));
  await tester.pumpAndSettle();

  final removeIconKeys = [
    'remove_icon_0',
    'remove_icon_1',
    'remove_icon_2',
  ];

  for (final iconKey in removeIconKeys) {
    await tester.tap(find.byKey(ValueKey(iconKey)));
    await tester.pumpAndSettle(Duration(seconds: 1));

    expect(find.text('Removed from favorites.'), findsOneWidget);
  }
});

Ejecuta la prueba

b2f84ff91b0e1396.pngConecta el dispositivo o inicia el emulador.

b2f84ff91b0e1396.pngEn la línea de comandos, navega al directorio raíz del proyecto y, luego, ingresa el siguiente comando:

$ flutter drive --driver integration_test/driver.dart --target integration_test/app_test.dart --profile

Si todo funciona, deberías ver un resultado similar al siguiente:

Running "flutter pub get" in step_07...                            930ms
Running Gradle task 'assembleProfile'...
Running Gradle task 'assembleProfile'... Done                      31.3s
✓ Built build/app/outputs/flutter-apk/app-profile.apk (11.3MB).
Installing build/app/outputs/flutter-apk/app.apk...                277ms
VMServiceFlutterDriver: Connecting to Flutter application at http://127.0.0.1:62862/K6QKjUNab8c=/
VMServiceFlutterDriver: Isolate found with number: 1935648057883071
VMServiceFlutterDriver: Isolate is paused at start.
VMServiceFlutterDriver: Attempting to resume isolate
I/flutter (24385): 00:00 +0: Testing App Performance Tests Scrolling test
VMServiceFlutterDriver: Connected to Flutter application.
I/flutter (24385): 00:08 +1: Testing App Performance Tests Favorites operations
test
I/flutter (24385): 00:17 +2: Testing App Performance Tests (tearDownAll)
I/flutter (24385): 00:17 +3: All tests passed!
All tests passed.

Una vez que la prueba se complete correctamente, el directorio build de la raíz del proyecto debe contener un archivo llamado integration_response_data.json. Contiene los datos de respuesta enviados desde la prueba mientras se ejecuta, en este caso, el elemento scrolling_summary. Para ver la información, abre el archivo con cualquier editor de texto. Con una configuración más avanzada, puedes guardar un resumen cada vez que se ejecuta la prueba y crear un gráfico de los resultados.

El archivo de prueba completo: integration_test/app_test.dart.

Para obtener más detalles sobre las pruebas de Flutter Driver (Integration), visita:

Completaste el codelab y aprendiste diferentes maneras de probar una app de Flutter.

Qué aprendiste

  • Cómo probar los widgets con el marco de trabajo de prueba del widget
  • Cómo probar la IU de la app mediante pruebas de integración
  • Cómo probar el rendimiento de la app mediante pruebas de integración
  • Cómo probar proveedores con la ayuda de pruebas de unidades

Para obtener más información sobre cómo hacer pruebas en Flutter, consulta lo siguiente: