How to do test your Flutter app

  • This tutorial requires you need to know BloC knowledge. If not, please read this document first.
  • Unit test: tests a single function, method, or class.
  • Widget test: (in other UI frameworks referred to as component test) tests a single widget.
  • Integration test: tests a complete app or a large part of an app.
https://flutter.dev/docs/testing
App structure
  • Which class you want to test: utils.dart
  • What method you want to test: isValidEmail
  • What input: trongdth@gmail.com
  • What output you expected: true
import 'package:flutter_bloc_back4app/helpers/utils.dart';
import 'package:flutter_test/flutter_test.dart';

void main() {
test('test email valid returns true', () {
/*
input: trongdth@gmail.com
expected: true
*/
var email = 'trongdth@gmail.com';
var actual = Utils.isValidEmail(email);
var expected = true;
expect(actual, expected);
});
}
  • When you create a new futter project. There is a sample code which has widget_test.dart under test folder. The code looks like this:
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:tokoin_wallet/main.dart';

void main() {
testWidgets('Counter increments smoke test', (WidgetTester tester) async {
// Build our app and trigger a frame.
await tester.pumpWidget(MyApp());

// Verify that our counter starts at 0.
expect(find.text('0'), findsOneWidget);
expect(find.text('1'), findsNothing);

// Tap the '+' icon and trigger a frame.
await tester.tap(find.byIcon(Icons.add));
await tester.pump();

// Verify that our counter has incremented.
expect(find.text('0'), findsNothing);
expect(find.text('1'), findsOneWidget);
});
}
  • Let's go through the code to understand what it does:
await tester.pumpWidget(MyApp()); // Load MyApp widget for testingexpect(find.text('0'), findsOneWidget); // use global object 'find' to find the widget has text '0'. The expectation is 'findsOneWidget'expect(find.text('1'), findsNothing); // use global object 'find' to find the widget has text '1'. The expectation is 'findsNothing'await tester.tap(find.byIcon(Icons.add)); // try to send the 'tap' action to the Icon widget which has 'Icons.add'await tester.pump(); // call 'build' function of the MyApp widgetexpect(find.text('0'), findsNothing); // use global object 'find' to find the widget has text '0'. The expectation is 'findsNothing'expect(find.text('1'), findsOneWidget); // use global object 'find' to find the widget has text '1'. The expectation is 'findsOneWidget'
  • Which widget you want to test: login.dart
  • Your scenario: based on app structure, if user logins unsuccessfully, you are still in the login page instead of the home page.
  • Create an abstract BaseUserRepository class:
abstract class BaseUserRepository {
Future<ParseUser> authenticate({@required String username, @required String email, @required String password,});
Future<ParseUser> signup({@required String username, @required String email, @required String password, });
Future<ParseUser> currentUser();
Future<bool> logout();
}
  • Create MockUserRepository extends from BaseUserRepository
class MockUserRepository extends BaseUserRepository {
ParseUser user;
bool isLogout;
MockUserRepository(); @override
Future<ParseUser> authenticate({String username, String email, String password}) {
var completer = new Completer<ParseUser>();
// At some time you need to complete the future:
completer.complete(user);
return completer.future;
}
@override
Future<ParseUser> currentUser() {
var completer = new Completer<ParseUser>();
// At some time you need to complete the future:
completer.complete(user);
return completer.future;
}
@override
Future<bool> logout() {
var completer = new Completer<bool>();
// At some time you need to complete the future:
completer.complete(isLogout);
return completer.future;
}
@override
Future<ParseUser> signup({String username, String email, String password}) {
var completer = new Completer<ParseUser>();
// At some time you need to complete the future:
completer.complete(user);
return completer.future;
}
}
  • Write a test:
Widget makeWidgetTestable({Widget child, LoginBloc loginBloc}) {
return MaterialApp(
home: BlocProvider<LoginBloc>(
builder: (context) {
return loginBloc;
},
child: child,
),
);
}
MockUserRepository mockUserRepository = MockUserRepository(); 
LoginBloc _loginBloc = LoginBloc(authBloc: AuthBloc(userRepository: mockUserRepository), userRepository: mockUserRepository);
LoginScreen screen = LoginScreen();
await tester.pumpWidget(makeWidgetTestable(child: screen, loginBloc: _loginBloc));
_loginBloc.dispatch(LoginButtonPressed(
username: 'trongdth',
email: 'trongdth@gmail.com',
password: '123456'
));
await tester.pump();
final loginKey = Key('BtnLogin');
expect(find.byKey(loginKey), findsOneWidget);
flutter test
  • Serverless: you (a mobile developer) can control your data, not depend on Backend and DevOps anymore.
  • Pricing: cheaper than AWS.
  • Push notification: send push notification at scale.

--

--

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Trong Dinh Thai Hoang

Trong Dinh Thai Hoang

39 Followers

I’m a peaceful person who wants to make friend with people around the world.