1. Introdução
O Flutter é um kit de ferramentas de IU do Google para criar apps incríveis e nativos para dispositivos móveis, Web e computadores com uma única base de código.
Neste codelab, você criará e testará um app simples do Flutter. Ele usará o pacote Provider (link em inglês) para gerenciar o estado.
O que você aprenderá
- Como criar testes usando o framework de testes de widgets.
- Como criar um teste de integração para testar a interface e o desempenho do app usando a biblioteca
integration_test
. - Como testar classes de dados (provedores) com a ajuda de testes de unidade.
O que você criará
Neste codelab, você começará criando um aplicativo simples com uma lista de itens. Fornecemos o código-fonte para que você consiga pular direto para os testes. O app é compatível com as seguintes operações:
- Adicionar itens aos favoritos
- Visualizar a lista de favoritos
- Remover itens da lista de favoritos
Depois que o app estiver pronto, você criará os seguintes testes:
| GIF do app executado no Android |
O que você quer aprender neste codelab?
2. Configurar o ambiente de desenvolvimento do Flutter
Você precisa de dois softwares para concluir este laboratório: o SDK do Flutter e um editor (links em inglês).
É possível executar o codelab usando qualquer um destes dispositivos:
- Um dispositivo físico Android ou iOS conectado ao computador e configurado para o modo de desenvolvedor.
- O simulador de iOS, que exige a instalação de ferramentas do Xcode.
- O Android Emulator, que requer configuração no Android Studio.
- Um navegador (o Chrome é necessário para depuração).
- Como um aplicativo para computador Windows, Linux ou macOS. Você precisa desenvolver na plataforma em que planeja implantar. Portanto, se quiser desenvolver um app para um computador Windows, você terá que desenvolver no Windows para acessar a cadeia de compilação adequada. Há requisitos específicos de cada sistema operacional que são abordados em detalhes em docs.flutter.dev/desktop (link em inglês).
3. Para começar
Criar um novo app do Flutter e atualizar as dependências
O foco deste codelab é testar um app do Flutter para dispositivos móveis. Você criará rapidamente o app que será testado, usando arquivos de origem que podem ser copiados e colados. O restante do codelab tem o objetivo de ensinar diferentes tipos de testes.
Programe um app do Flutter simples usando um modelo e seguindo as instruções em Como começar seu primeiro app Flutter (link em inglês) ou na linha de comando, como mostrado a seguir.
$ flutter create testing_app
Adicione dependências de pub na linha de comando. Para fácil gerenciamento do estado, adicione provider
:
$ cd testing_app $ flutter pub add provider Resolving dependencies... collection 1.17.0 (1.17.1 available) js 0.6.5 (0.6.7 available) matcher 0.12.13 (0.12.14 available) meta 1.8.0 (1.9.0 available) + nested 1.0.0 path 1.8.2 (1.8.3 available) + provider 6.0.5 test_api 0.4.16 (0.4.18 available) Changed 2 dependencies!
Para testes de direção autônoma do código do Flutter em dispositivos e emuladores, adicione integration_test
:
$ flutter pub add --dev --sdk=flutter integration_test Resolving dependencies... + archive 3.3.2 (3.3.6 available) collection 1.17.0 (1.17.1 available) + crypto 3.0.2 + file 6.1.4 + flutter_driver 0.0.0 from sdk flutter + fuchsia_remote_debug_protocol 0.0.0 from sdk flutter + integration_test 0.0.0 from sdk flutter js 0.6.5 (0.6.7 available) matcher 0.12.13 (0.12.14 available) meta 1.8.0 (1.9.0 available) path 1.8.2 (1.8.3 available) + platform 3.1.0 + process 4.2.4 + sync_http 0.3.1 test_api 0.4.16 (0.4.18 available) + typed_data 1.3.1 + vm_service 9.4.0 (11.0.1 available) + webdriver 3.0.1 (3.0.2 available) Changed 12 dependencies!
Para uma API avançada para testar aplicativos do Flutter executados em dispositivos reais e emuladores, adicione flutter_driver
:
$ flutter pub add --dev --sdk=flutter flutter_driver Resolving dependencies... archive 3.3.2 (3.3.6 available) collection 1.17.0 (1.17.1 available) js 0.6.5 (0.6.7 available) matcher 0.12.13 (0.12.14 available) meta 1.8.0 (1.9.0 available) path 1.8.2 (1.8.3 available) test_api 0.4.16 (0.4.18 available) vm_service 9.4.0 (11.0.1 available) webdriver 3.0.1 (3.0.2 available) Got dependencies!
Para ferramentas gerais de teste, adicione test
:
$ flutter pub add --dev test Resolving dependencies... + _fe_analyzer_shared 52.0.0 + analyzer 5.4.0 archive 3.3.2 (3.3.6 available) + args 2.3.2 collection 1.17.0 (1.17.1 available) + convert 3.1.1 + coverage 1.6.3 + frontend_server_client 3.2.0 + glob 2.1.1 + http_multi_server 3.2.1 + http_parser 4.0.2 + io 1.0.4 js 0.6.5 (0.6.7 available) + logging 1.1.1 matcher 0.12.13 (0.12.14 available) meta 1.8.0 (1.9.0 available) + mime 1.0.4 + node_preamble 2.0.1 + package_config 2.1.0 path 1.8.2 (1.8.3 available) + pool 1.5.1 + pub_semver 2.1.3 + shelf 1.4.0 + shelf_packages_handler 3.0.1 + shelf_static 1.1.1 + shelf_web_socket 1.0.3 + source_map_stack_trace 2.1.1 + source_maps 0.10.11 + test 1.22.0 (1.23.0 available) test_api 0.4.16 (0.4.18 available) + test_core 0.4.20 (0.4.23 available) vm_service 9.4.0 (11.0.1 available) + watcher 1.0.2 + web_socket_channel 2.3.0 webdriver 3.0.1 (3.0.2 available) + webkit_inspection_protocol 1.2.0 + yaml 3.1.1 Changed 28 dependencies!
Para processar a navegação no app, adicione go_router:
$ flutter pub add go_router Resolving dependencies... archive 3.3.2 (3.3.6 available) collection 1.17.0 (1.17.1 available) + flutter_web_plugins 0.0.0 from sdk flutter + go_router 6.0.4 js 0.6.5 (0.6.7 available) matcher 0.12.13 (0.12.14 available) meta 1.8.0 (1.9.0 available) path 1.8.2 (1.8.3 available) test 1.22.0 (1.23.0 available) test_api 0.4.16 (0.4.18 available) test_core 0.4.20 (0.4.23 available) vm_service 9.4.0 (11.0.1 available) webdriver 3.0.1 (3.0.2 available) Changed 2 dependencies!
As seguintes dependências precisam estar no seu pubspec.yaml:
Em dependencies
:
dependencies: provider: ^6.0.5 go_router: ^6.0.4
Em dev_dependencies
:
dev_dependencies: integration_test: sdk: flutter flutter_driver: sdk: flutter test: ^1.22.0
Abra o projeto no editor de código de sua escolha e execute o app. É possível também executar na linha de comando, como mostrado abaixo.
$ flutter run
4. Criar o app
Em seguida, você criará o app para testá-lo. O app contém os seguintes arquivos:
lib/models/favorites.dart
: cria a classe de modelo para a lista de favoritos.lib/screens/favorites.dart
: cria o layout da lista de favoritos.lib/screens/home.dart
: cria uma lista de itens.lib/main.dart
: arquivo principal em que o app é iniciado.
Primeiro, crie o modelo Favorites
em lib/models/favorites.dart
Crie um novo diretório chamado models
no diretório lib
, depois crie um novo arquivo chamado favorites.dart
. Nesse arquivo, adicione o seguinte 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();
}
}
Adicionar a página de favoritos ao lib/screens/favorites.dart
Crie um novo diretório chamado screens
no diretório lib
. Nesse diretório, crie um novo arquivo chamado favorites.dart
. Nesse arquivo, adicione o seguinte código:
lib/screens/favorites.dart
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import '../models/favorites.dart';
class FavoritesPage extends StatelessWidget {
const FavoritesPage({super.key});
static String routeName = 'favorites_page';
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const 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 {
const FavoriteItemTile(this.itemNo, {super.key});
final int 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: const Icon(Icons.close),
onPressed: () {
Provider.of<Favorites>(context, listen: false).remove(itemNo);
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content: Text('Removed from favorites.'),
duration: Duration(seconds: 1),
),
);
},
),
),
);
}
}
Adicionar a página inicial ao lib/screens/home.dart
No diretório lib/screens
, crie outro arquivo chamado home.dart
. No lib/screens/home.dart
, adicione o seguinte código:
lib/screens/home.dart
import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';
import 'package:provider/provider.dart';
import '../models/favorites.dart';
import 'favorites.dart';
class HomePage extends StatelessWidget {
static String routeName = '/';
const HomePage({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Testing Sample'),
actions: <Widget>[
TextButton.icon(
onPressed: () {
context.go('/${FavoritesPage.routeName}');
},
icon: const Icon(Icons.favorite_border),
label: const 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, {super.key});
@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)
? const Icon(Icons.favorite)
: const 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: const Duration(seconds: 1),
),
);
},
),
),
);
}
}
Substituir o conteúdo do lib/main.dart
Substitua o conteúdo do lib/main.dart
pelo seguinte código:
lib/main.dart
import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';
import 'package:provider/provider.dart';
import 'models/favorites.dart';
import 'screens/favorites.dart';
import 'screens/home.dart';
void main() {
runApp(const TestingApp());
}
final _router = GoRouter(
routes: [
GoRoute(
path: HomePage.routeName,
builder: (context, state) {
return const HomePage();
},
routes: [
GoRoute(
path: FavoritesPage.routeName,
builder: (context, state) {
return const FavoritesPage();
},
),
],
),
],
);
class TestingApp extends StatelessWidget {
const TestingApp({super.key});
@override
Widget build(BuildContext context) {
return ChangeNotifierProvider<Favorites>(
create: (context) => Favorites(),
child: MaterialApp.router(
title: 'Testing Sample',
theme: ThemeData(
primarySwatch: Colors.blue,
useMaterial3: true,
),
routerConfig: _router,
),
);
}
}
O app está concluído, mas ainda não foi testado.
Execute o app. Ele vai ficar parecido com a seguinte captura de tela:
O app exibe uma lista de itens. Toque no ícone em formato de coração em qualquer linha para preencher o coração e adicionar o item à lista de favoritos. O botão Favorites na AppBar
leva a uma segunda tela que contém a lista de favoritos.
Agora o app está pronto para ser testado. Você vai começar os testes na próxima etapa.
5. Testes de unidade do provedor
Comece fazendo um teste de unidade do modelo favorites
. O que é esse teste? Um teste de unidade verifica se cada unidade do software, seja ela uma função, objeto ou widget, executa a tarefa pretendida de modo correto.
Todos os arquivos de teste de um app do Flutter, exceto os testes de integração, são colocados no diretório test
.
Remover o test/widget_test.dart
Antes de iniciar o teste, exclua o arquivo widget_test.dart
. Você adicionará seus próprios arquivos de teste.
Criar um novo arquivo de teste
Primeiro, você testará o método add()
no modelo Favorites
para verificar se um novo item foi adicionado à lista e se ela reflete essa mudança. Por convenção, a estrutura no diretório test
imita a do diretório lib
e os arquivos Dart têm o mesmo nome, mas com o anexo _test
.
Crie um diretório models
no test
. Nesse novo diretório, crie um arquivo favorites_test.dart
com o seguinte conteúdo:
test/models/favorites_test.dart
import 'package:test/test.dart';
import 'package:testing_app/models/favorites.dart';
void main() {
group('Testing App Provider', () {
var favorites = Favorites();
test('A new item should be added', () {
var number = 35;
favorites.add(number);
expect(favorites.items.contains(number), true);
});
});
}
O framework de testes do Flutter permite vincular testes semelhantes, que são relacionados entre si, em um grupo. Podem existir vários grupos em um único arquivo de teste destinados a testar partes diferentes do arquivo correspondente no diretório lib
.
O método test()
usa dois parâmetros de posicionamento: a description
do teste e o callback
em que o teste é criado.
Teste a remoção de um item da lista. Insira o teste a seguir no mesmo grupo Testing App Provider
:
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);
});
Executar o teste
Na linha de comando, navegue até o diretório raiz do projeto e digite o seguinte comando:
$ flutter test test/models/favorites_test.dart
Se tudo funcionar, você verá uma mensagem parecida com a seguinte:
00:06 +2: All tests passed!
Veja o arquivo de teste completo: test/models/favorites_test.dart
(link em inglês).
Para ver mais informações sobre o teste de unidade, acesse Introdução ao teste de unidade (link em inglês).
6. Teste de widget
Nesta etapa, você vai adicionar código para testar widgets. Os testes de widget são exclusivos do Flutter. Com eles, é possível testar cada widget isoladamente. Nesta etapa, as telas HomePage
e FavoritesPage
serão testadas individualmente.
O teste de widget usa a função testWidget()
, e não a test()
. Assim como a função test()
, a testWidget()
recebe dois parâmetros: description,
e callback
. Porém, o callback recebe um WidgetTester
como argumento.
Os testes de widget usam a TestFlutterWidgetsBinding
, uma classe que oferece os mesmos recursos que os widgets teriam em um app em execução, como informações sobre o tamanho da tela e a capacidade de programar animações, mas sem executar no app real. Em vez disso, um ambiente virtual é usado para instanciar o widget e, depois, testar os resultados. Aqui, o pumpWidget
inicia o processo instruindo o framework a ativar e medir um widget específico, da mesma forma que seria feito em um aplicativo.
O framework de teste de widget fornece finders para encontrar widgets, como text()
, byType()
e byIcon().
. O framework também fornece matchers para analisar os resultados.
Comece testando o widget HomePage
.
Criar um novo arquivo de teste
O primeiro teste verifica se a rolagem da HomePage
funciona corretamente.
Crie um novo arquivo no diretório test
e nomeie-o como home_test.dart
. Adicione o seguinte código no arquivo criado:
test/home_test.dart (link em inglês)
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: const 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),
const Offset(0, -200),
3000,
);
await tester.pumpAndSettle();
expect(find.text('Item 0'), findsNothing);
});
});
}
A função createHomeScreen()
é usada para criar um app que carrega o widget a ser testado em um MaterialApp, envolvido em um ChangeNotifierProvider. O widget da página inicial precisa que os dois estejam presentes acima dele na árvore de widgets, para que ele consiga herdar e ter acesso aos dados fornecidos por eles. Essa função é transmitida como um parâmetro para a função pumpWidget()
.
Em seguida, teste se o framework consegue encontrar uma ListView
renderizada na tela.
Adicione o seguinte snippet de código a home_test.dart
:
test/home_test.dart (link em inglês)
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),
const Offset(0, -200),
3000,
);
await tester.pumpAndSettle();
expect(find.text('Item 0'), findsNothing);
});
});
Executar o teste
Primeiro, execute o teste da mesma maneira que você faria com um teste de unidade, com o comando:
$ flutter test test/home_test.dart
O teste é rápido, e uma mensagem como esta será exibida:
00:02 +2: All tests passed!
Você também pode testar widgets usando um dispositivo ou emulador, que permite assistir à execução do teste. Isso também possibilita usar a recarga dinâmica.
Conecte o dispositivo ou inicie o emulador. Também é possível executar o teste como um aplicativo de computador.
Na linha de comando, navegue até o diretório raiz do projeto e digite o seguinte comando:
$ flutter run test/home_test.dart
Pode ser necessário selecionar o dispositivo em que será executado o teste. Nesse caso, siga as instruções e selecione um dispositivo:
Multiple devices found:
Linux (desktop) • linux • linux-x64 • Ubuntu 22.04.1 LTS 5.15.0-58-generic
Chrome (web) • chrome • web-javascript • Google Chrome 109.0.5414.119
[1]: Linux (linux)
[2]: Chrome (chrome)
Please choose one (To quit, press "q/Q"):
Se tudo funcionar, você receberá uma resposta parecida com a seguinte:
Launching test/home_test.dart on Linux in debug mode...
Building Linux application...
flutter: 00:00 +0: Home Page Widget Tests Testing if ListView shows up
Syncing files to device Linux... 62ms
Flutter run key commands.
r Hot reload. 🔥🔥🔥
R Hot restart.
h List all available interactive commands.
d Detach (terminate "flutter run" but leave application running).
c Clear the screen
q Quit (terminate the application on the device).
💪 Running with sound null safety 💪
An Observatory debugger and profiler on Linux is available at: http://127.0.0.1:35583/GCpdLBqf2UI=/
flutter: 00:00 +1: Home Page Widget Tests Testing Scrolling
The Flutter DevTools debugger and profiler on Linux is available at:
http://127.0.0.1:9100?uri=http://127.0.0.1:35583/GCpdLBqf2UI=/
flutter: 00:02 +2: All tests passed!
Em seguida, faça mudanças no arquivo de teste e pressione Shift + R
para fazer uma recarga dinâmica do app. Depois, execute todos os testes de novo. Não pare o aplicativo.
Adicione mais testes ao grupo que testa os widgets da página inicial. Copie o teste a seguir e cole no arquivo:
test/home_test.dart (link em inglês)
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(const 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(const Duration(seconds: 1));
expect(find.text('Removed from favorites.'), findsOneWidget);
expect(find.byIcon(Icons.favorite), findsNothing);
});
Esse teste verifica se, com um toque, o IconButton
muda de Icons.favorite_border
(coração vazio) para Icons.favorite
(coração preenchido) e volta para Icons.favorite_border
com outro toque.
Digite Shift + R
. Isso faz uma recarga dinâmica do app e executa todos os apps novamente.
Veja o arquivo de teste completo em: test/home_test.dart
.
(link em inglês).
Use o mesmo processo para testar a FavoritesPage
com o código a seguir. Siga as mesmas etapas e execute o teste.
test/favorites_test.dart (link em inglês)
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';
late Favorites favoritesList;
Widget createFavoritesScreen() => ChangeNotifierProvider<Favorites>(
create: (context) {
favoritesList = Favorites();
return favoritesList;
},
child: const 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);
});
});
}
Este teste verifica se um item desaparece quando o botão Fechar (remover) é pressionado.
Para ver mais informações sobre testes de widgets, acesse (links em inglês):
7. Como testar a interface do app com testes de integração
Os testes de integração são usados para testar a forma como as partes individuais de um app funcionam em conjunto. A biblioteca integration_test
(link em inglês) é usada para fazer testes de integração no Flutter. Essa é a versão do Flutter para o Selenium WebDriver, Protractor, Espresso ou Earl Gray. O pacote usa flutter_driver
(link em inglês) internamente para controlar o teste em um dispositivo.
A criação de testes de integração no Flutter é semelhante à criação de testes para widgets, exceto que os testes de integração são executados em um dispositivo móvel, navegador ou aplicativo de computador, chamado de dispositivo de destino.
Criar o teste
Crie um diretório chamado integration_test
no diretório raíz do projeto e, dentro dele, um arquivo novo chamado app_test.dart
.
integration_test/app_test.dart (link em inglês)
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:testing_app/main.dart';
void main() {
group('Testing App', () {
testWidgets('Favorites operations test', (tester) async {
await tester.pumpWidget(const TestingApp());
final iconKeys = [
'icon_0',
'icon_1',
'icon_2',
];
for (var icon in iconKeys) {
await tester.tap(find.byKey(ValueKey(icon)));
await tester.pumpAndSettle(const 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(const Duration(seconds: 1));
expect(find.text('Removed from favorites.'), findsOneWidget);
}
});
});
}
Executar o teste
Conecte o dispositivo ou inicie o emulador. Também é possível executar o teste como um aplicativo de computador.
Na linha de comando, navegue até o diretório raiz do projeto e digite o seguinte comando:
$ flutter test integration_test/app_test.dart
Se tudo funcionar, você vai receber uma resposta parecida com a seguinte:
Multiple devices found:
Linux (desktop) • linux • linux-x64 • Ubuntu 22.04.1 LTS 5.15.0-58-generic
Chrome (web) • chrome • web-javascript • Google Chrome 109.0.5414.119
[1]: Linux (linux)
[2]: Chrome (chrome)
Please choose one (To quit, press "q/Q"): 1
00:00 +0: loading /home/miquel/tmp/testing_app/integration_test/app_test.dart B00:08 +0: loading /home/miquel/tmp/testing_app/integration_test/app_test.dart
00:26 +1: All tests passed!
8. Como testar o desempenho do app com o driver do Flutter
Criar um teste de desempenho
Crie um novo arquivo de teste chamado perf_test.dart na pasta integration_test com o seguinte conteúdo:
integration_test/perf_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', () {
final binding = IntegrationTestWidgetsFlutterBinding.ensureInitialized();
binding.framePolicy = LiveTestWidgetsFlutterBindingFramePolicy.fullyLive;
testWidgets('Scrolling test', (tester) async {
await tester.pumpWidget(const TestingApp());
final listFinder = find.byType(ListView);
await binding.traceAction(() async {
await tester.fling(listFinder, const Offset(0, -500), 10000);
await tester.pumpAndSettle();
await tester.fling(listFinder, const Offset(0, 500), 10000);
await tester.pumpAndSettle();
}, reportKey: 'scrolling_summary');
});
});
}
A função ensureInitialized()
verifica se o driver do teste de integração foi inicializado e reinicia o driver, se necessário. Configurar framePolicy
como fullyLive
é bom para testar código animado.
Este teste percorre a lista de itens com muita rapidez e, em seguida, rola a página para cima até o início. A função traceAction()
registra as ações e gera um resumo da linha do tempo.
Capturar os resultados do desempenho
Para capturar os resultados, crie uma pasta chamada test_driver
, com um arquivo perf_driver.dart
e adicione o seguinte código:
test_driver/perf_driver.dart
import 'package:flutter_driver/flutter_driver.dart' as driver;
import 'package:integration_test/integration_test_driver.dart';
Future<void> main() {
return integrationDriver(
responseDataCallback: (data) async {
if (data != null) {
final timeline = driver.Timeline.fromJson(
data['scrolling_summary'] as Map<String, dynamic>);
final summary = driver.TimelineSummary.summarize(timeline);
await summary.writeTimelineToFile(
'scrolling_summary',
pretty: true,
includeSummary: true,
);
}
},
);
}
Executar o teste
Conecte o dispositivo ou inicie o emulador.
Na linha de comando, navegue até o diretório raiz do projeto e digite o seguinte comando:
$ flutter drive \
--driver=test_driver/perf_driver.dart \
--target=integration_test/perf_test.dart \
--profile \
--no-dds
Se tudo funcionar, você vai receber uma resposta parecida com a seguinte:
Running "flutter pub get" in testing_app...
Resolving dependencies...
archive 3.3.2 (3.3.6 available)
collection 1.17.0 (1.17.1 available)
js 0.6.5 (0.6.7 available)
matcher 0.12.13 (0.12.14 available)
meta 1.8.0 (1.9.0 available)
path 1.8.2 (1.8.3 available)
test 1.22.0 (1.23.0 available)
test_api 0.4.16 (0.4.18 available)
test_core 0.4.20 (0.4.23 available)
vm_service 9.4.0 (11.0.1 available)
webdriver 3.0.1 (3.0.2 available)
Got dependencies!
Running Gradle task 'assembleProfile'... 1,379ms
✓ Built build/app/outputs/flutter-apk/app-profile.apk (14.9MB).
Installing build/app/outputs/flutter-apk/app-profile.apk... 222ms
I/flutter ( 6125): 00:04 +1: Testing App Performance (tearDownAll)
I/flutter ( 6125): 00:04 +2: All tests passed!
All tests passed.
Quando o teste estiver concluído, o diretório de build na raiz do projeto terá dois arquivos:
scrolling_summary.timeline_summary.json
contém o resumo. Abra o arquivo com qualquer editor de texto para revisar as informações.scrolling_summary.timeline.json
contém os dados completos da linha do tempo.
Para mais detalhes sobre o teste de integração, visite:
9. Parabéns!
Você concluiu o codelab e aprendeu formas diferentes de testar um app do Flutter.
O que você aprendeu
- Como testar provedores com a ajuda dos testes de unidade
- Como testar widgets usando o framework de testes de widgets.
- Como testar a IU do app usando testes de integração.
- Como testar o desempenho do app usando testes de integração.
Para saber mais sobre os testes no Flutter, acesse (links em inglês):