Unit- Widget and Integration Testing
Unit- Widget and Integration Testing
Testing
Learning Outcomes
After completing this session you should be able to
External dependencies of the unit under test are generally mocked out
Unit tests generally don’t read from or write to disk, render to screen, or
receive user actions from outside the process running the test
For more information regarding unit tests, you can view the following recipes
or run
The goal of a widget test is to verify that the widget’s UI looks and interacts
as expected
The goal of an integration test is to verify that all the widgets and services
being tested work together as expected
The app under test is typically isolated from the test driver code to avoid
skewing the results
General Testing Procedure in Flutter
To perform tests in flutter you can follow the following steps
● Add the required dependencies in the pubspec.yaml
● Create a test files (should have _test.dart suffix)
● Identify the classes, functions, widgets or flutter application that you want
to test
● Write tests
● Combine multiple tests in a group if needed
● Run the tests
General Directory Structure for Testing
Unit Testing - Add the test dependency
The test package provides the core functionality for writing tests in Dart
Add the dependency shown below in your pubspec.yaml file or run the
command:
flutter pub add test --dev
Unit Testing - Create a test file
Let us assume we want to test the following class - a unit
class Counter {
int value = 0;
void increment() => value++;
void decrement() => value--;
}
Test Directory and File Naming
In general, unit test files should reside inside a
test folder located at the root of your Flutter
application or package
For more options regarding unit tests, you can execute this command:
blocTest(
'emits [1] when CounterIncrementPressed is added',
build: () => CounterBloc(),
act: (bloc) => bloc.add(CounterIncrementPressed()),
expect: () => [1],
);
});
Bloc Test (counter_bloc_test.dart)
blocTest<CounterBloc, int>(
'emits [] when no event is added',
build: () => CounterBloc(),
expect: () => const [],
);
Bloc Test (counter_bloc_test.dart)
blocTest<CounterBloc, int>(
'emit [1] when CounterIncrementPressed is added',
build: () => CounterBloc(),
act: (bloc) => bloc.add(CounterIncrementPressed()),
expect: () => [1],
);
Bloc Test (counter_bloc_test.dart)
blocTest<CounterBloc, int>(
'emit [-1] when CounterDecrementPressed() is added',
build: () => CounterBloc(),
act: (bloc) => bloc.add(CounterDecrementPressed()),
expect: () => [-1],
);
https://pub.dev/packages/bloc_test/example
Mocking Dependencies
In most cases classes depend on other classes that fetch data from live web
services or databases, for instance
Mocks allow emulating a live web service or database and return deterministic
results depending on preconfigured setup/situation
@GenerateMocks([http.Client])
void main() {
}
});
Testing fetchAlbum(http.Client) function
test('throws an exception if the http call completes with an error',
() {
final client = MockClient();
when(client
.get(Uri.parse('https://jsonplaceholder.typicode.com/albums/1')))
.thenAnswer((_) async => http.Response('Not Found', 404));
expect(fetchAlbum(client), throwsException);
});
});
void main() {
testWidgets('MyWidget has a title and message',
(WidgetTester tester) async {
// Test code goes here.
});
}
Build the widget using the WidgetTester
void main() {
await tester.pumpWidget(
});
}
Build the widget using the WidgetTester
Variations of tester.pumpWidget() function
tester.pump(Duration duration)
tester.pumpAndSettle()
We are looking for for Text widgets, therefore we should use the
find.text() method
Search for widgets using a Finder
void main() {
testWidgets('MyWidget displays title and message',
(WidgetTester tester) async {
await tester
.pumpWidget(MyWidget(title: 'Test 123', message: 'Message 123'));
expect(tittleFinder, findsOneWidget);
expect(messageFinder, findsWidgets);
});
}
Other Finders
To find a widget with a specific Key
testWidgets('finds a widget using a Key', (WidgetTester tester) async {
// Define the test key.
const testKey = Key('K');
expect(titleFinder, findsOneWidget);
expect(messageFinder, findsOneWidget);
});
}
Other Matchers
findsNothing
findsWidgets
matchesGoldenFile
https://flutter.dev/docs/cookbook/testing/widget/tap-drag
Tap, drag, and enter text
testWidgets('Counter increments smoke test', (WidgetTester tester) async {
// Build our app and trigger a frame.
await tester.pumpWidget(MyApp());
An integration test (also called end-to-end testing or GUI testing) runs the
full app
Integration Testing
Hosts and targets
The machine you are using for developing the application, writing and
running tests is called Host Machine
The emulator, the mobile device or the browser which run the flutter
application is called Target Device
Integration Testing
flutter_driver
Tests written with flutter_driver run from the host and drive the
app running on a real or virtual device
The flutter drive command is used to run tests written with this package
Integration Testing
integration_test
Tests written with the integration_test package can:
● Run directly on the target device, allowing you to test on multiple Android
or iOS devices using Firebase Test Lab.
● Run using flutter_driver.
● Use flutter_test APIs, making integration tests more like writing widget
tests.
Integration Testing
In your project, create a new directory integration_test/ with a new file,
<name>_test.dart
void main() {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
import 'package:integration_test/integration_test_driver.dart';
Future<void> main() => integrationDriver();
https://github.com/flutter/flutter/tree/master/packages/integration_test#usage
Example Unit, Widget, and Integration Test
Check the following example to see all three tests together
https://codelabs.developers.google.com/codelabs/flutter-app-testing/
References
https://flutter.dev/docs/cookbook (Testing section)
https://riverpod.dev/docs/cookbooks/testing