Rafael Almeida Barbosa
Desenvolvedor Mobile, Palestrante, Pai coruja! Apaixonado por inovações e soluções que cabem na palma da mão!
Testando nossa aplicação
Rafael Almeida Barbosa
Android/Flutter Developer - Cofundador Lovepeople
Cofundador FlutterSP
1 - 35
2 - 35
2 - 35
3 - 35
Um teste de unidade testa uma única função, método ou classe. O objetivo de um teste de unidade é verificar a exatidão de uma unidade de lógica sob uma variedade de condições.
3 - 35
Um teste de widget (em outras estruturas de interface do usuário conhecidas como teste de componente) testa um único widget. O objetivo de um teste de widget é verificar se a interface do usuário do widget parece e interage conforme o esperado. Testar um widget envolve várias classes e requer um ambiente de teste que forneça o contexto apropriado do ciclo de vida do widget.
3 - 35
Testes de unidade e testes de widget são úteis para testar classes, funções ou widgets individuais. No entanto, eles geralmente não testam como peças individuais funcionam juntas como um todo ou capturam o desempenho de um aplicativo executado em um dispositivo real. Essas tarefas são executadas com testes de integração.
4 - 35
dev_dependencies:
test: <latest_version>
4 - 35
counter_app/
lib/
counter.dart
test/
counter_test.dart
4 - 35
class Counter {
int value = 0;
void increment() => value++;
void decrement() => value--;
}
4 - 35
// Import the test package and Counter class
import 'package:test/test.dart';
import 'package:counter_app/counter.dart';
void main() {
test('Counter value should be incremented', () {
final counter = Counter();
counter.increment();
expect(counter.value, 1);
});
}
4 - 35
flutter test test/counter_test.dart
4 - 35
Vamos fazer juntos
4 - 35
dev_dependencies:
flutter_test:
sdk: flutter
4 - 35
class MyWidget extends StatelessWidget {
const MyWidget({
Key? key,
required this.title,
required this.message,
}) : super(key: key);
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),
),
),
);
}
}
4 - 35
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', (WidgetTester tester) async {
// Test code goes here.
});
}
4 - 35
void main() {
testWidgets('MyWidget has a title and message', (WidgetTester tester) async {
// Create the widget by telling the tester to build it.
await tester.pumpWidget(const MyWidget(title: 'T', message: 'M'));
});
}
4 - 35
Após o pumpWidget o 'WidgetTester' disponibiliza outras maneiras de fazer um rebuild do widget:
4 - 35
void main() {
testWidgets('MyWidget has a title and message', (WidgetTester tester) async {
await tester.pumpWidget(const MyWidget(title: 'T', message: 'M'));
// Create the Finders.
final titleFinder = find.text('T');
final messageFinder = find.text('M');
});
}
4 - 35
void main() {
testWidgets('MyWidget has a title and message', (WidgetTester 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);
});
}
4 - 35
expectLater(
find.byType(MaterialApp),
matchesGoldenFile('./golden_files/minha_tela.png'),
);
4 - 35
void main() {
testWidgets('MyWidget has a title and message', (WidgetTester 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);
expectLater(
find.byType(MyWidget),
matchesGoldenFile('./golden_files/my_widget.png'),
);
});
}
4 - 35
flutter test --update-goldens {path-file-teste}
Pronto ele irá criar uma imagem que servirá como modelo de verificação na pasta especificada ('./golden_files/minha_tela.png').
Sempre que rodar o teste ele vai verificar o que foi desenhado com a foto modelo.
4 - 35
Vamos fazer juntos
4 - 35
4 - 35
4 - 35
4 - 35
dev_dependencies:
integration_test:
sdk: flutter
flutter_test:
sdk: flutter
4 - 35
lib/
...
integration_test/
foo_test.dart
bar_test.dart
test/
# Other unit tests go here.
4 - 35
import 'package:flutter_test/flutter_test.dart';
import 'package:integration_test/integration_test.dart';
void main() {
IntegrationTestWidgetsFlutterBinding.ensureInitialized(); // NEW
binding.framePolicy = LiveTestWidgetsFlutterBindingFramePolicy.fullyLive; // NEW
testWidgets('should load screen', (tester) async {
/// Escreve o teste similar ao teste de widget
});
}
4 - 35
flutter test integration_test/foo_test.dart -d <DEVICE_ID>
flutter test integration_test
4 - 35
Vamos fazer juntos
4 - 35
pushd android
# flutter build generates files in android/ for building the app
flutter build apk
./gradlew app:assembleAndroidTest
./gradlew app:assembleDebug -Ptarget=integration_test/<name>_test.dart
popd
4 - 35
<flutter_project_directory>/build/app/outputs/apk/debug/<file>.apk
<flutter_project_directory>/build/app/outputs/apk/androidTest/debug/<file>.apk
4 - 35
4 - 35
await binding.traceAction(
() async {
// Scroll until the item to be found appears.
await tester.scrollUntilVisible(
itemFinder,
500.0,
scrollable: listFinder,
);
},
reportKey: 'scrolling_timeline',
);
4 - 35
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_timeline']);
final summary = driver.TimelineSummary.summarize(timeline);
// Then, write the entire timeline to disk in a json format.
// This file can be opened in the Chrome browser's tracing tools
// found by navigating to chrome://tracing.
// Optionally, save the summary to disk by setting includeSummary
// to true
await summary.writeTimelineToFile(
'scrolling_timeline',
pretty: true,
includeSummary: true,
);
}
},
);
}
Criar um arquivo chamado `perf_driver.dart` (custom `test_driver`)
4 - 35
flutter drive \
--driver=test_driver/perf_driver.dart \
--target=integration_test/scrolling_test.dart \
--profile
4 - 35
scrolling_summary.timeline_summary.json
Nesse arquivo contem o sumário da performance. Os dados macro
scrolling_timeline.timeline.json
Nesse arquivo contem toda a timeline e pode ser aberto em chrome://tracing para ser analisado
Obrigado!
GithubPage: http://rafaelbarbosatec.github.io
LInkedln: https://www.linkedin.com/in/rafael-almeida-7667a063
Medium: @rafaelbarbosatec
By Rafael Almeida Barbosa
Desenvolvedor Mobile, Palestrante, Pai coruja! Apaixonado por inovações e soluções que cabem na palma da mão!