1. Giới thiệu
Flutter là bộ công cụ giao diện người dùng của Google để xây dựng những ứng dụng đẹp mắt, được biên dịch tự nhiên cho thiết bị di động, web và máy tính chỉ từ một cơ sở mã duy nhất.
Trong lớp học lập trình này, bạn sẽ xây dựng và kiểm thử một ứng dụng Flutter đơn giản. Ứng dụng sẽ sử dụng gói Provider để quản lý trạng thái.
Kiến thức bạn sẽ học được
- Cách tạo bài kiểm thử tiện ích bằng khung kiểm thử tiện ích
- Cách tạo bài kiểm thử tích hợp để kiểm thử hiệu suất và giao diện người dùng của ứng dụng bằng cách sử dụng thư viện
integration_test
- Cách kiểm thử các lớp dữ liệu (nhà cung cấp) với sự trợ giúp của kiểm thử đơn vị
Sản phẩm bạn sẽ tạo ra
Trong lớp học lập trình này, bạn sẽ bắt đầu bằng cách xây dựng một ứng dụng đơn giản với danh sách các mục. Chúng tôi sẽ cung cấp mã nguồn cho bạn để bạn có thể tham gia ngay thử nghiệm. Ứng dụng hỗ trợ các thao tác sau:
- Đang thêm mục vào danh sách yêu thích
- Xem danh sách mục yêu thích
- Đang xoá các mục khỏi danh sách yêu thích
Sau khi ứng dụng hoàn tất, bạn sẽ viết các mã kiểm thử sau:
| Ảnh GIF của ứng dụng chạy trên Android |
Bạn muốn tìm hiểu gì từ lớp học lập trình này?
2. Thiết lập môi trường phát triển Flutter
Bạn cần có 2 phần mềm để hoàn thành phòng thí nghiệm này – Flutter SDK và trình chỉnh sửa.
Bạn có thể chạy lớp học lập trình bằng bất kỳ thiết bị nào sau đây:
- Một thiết bị Android hoặc iOS thực kết nối với máy tính của bạn và được đặt ở Chế độ nhà phát triển.
- Trình mô phỏng iOS (yêu cầu cài đặt công cụ Xcode).
- Trình mô phỏng Android (yêu cầu thiết lập trong Android Studio).
- Trình duyệt (cần có Chrome để gỡ lỗi).
- Dưới dạng ứng dụng Windows, Linux hoặc macOS. Bạn phải phát triển trên nền tảng mà bạn dự định triển khai. Vì vậy, nếu muốn phát triển một ứng dụng Windows dành cho máy tính, bạn phải phát triển trên Windows để truy cập vào chuỗi bản dựng phù hợp. Có các yêu cầu cụ thể theo hệ điều hành được đề cập chi tiết trên docs.flutter.dev/desktop.
3. Bắt đầu
Tạo một ứng dụng Flutter mới và cập nhật phần phụ thuộc
Lớp học lập trình này tập trung vào việc kiểm thử ứng dụng di động Flutter. Bạn sẽ nhanh chóng tạo ứng dụng cần kiểm thử bằng cách sử dụng các tệp nguồn mà bạn sao chép và dán. Sau đó, phần còn lại của lớp học lập trình sẽ tập trung vào việc tìm hiểu các loại hình kiểm thử.
Tạo một ứng dụng Flutter theo mẫu đơn giản bằng cách làm theo hướng dẫn trong bài viết Bắt đầu sử dụng ứng dụng Flutter đầu tiên hoặc trên dòng lệnh như sau.
$ flutter create --empty testing_app Creating project testing_app... Resolving dependencies in `testing_app`... Downloading packages... Got dependencies in `testing_app`. Wrote 128 files. All done! You can find general documentation for Flutter at: https://docs.flutter.dev/ Detailed API documentation is available at: https://api.flutter.dev/ If you prefer video documentation, consider: https://www.youtube.com/c/flutterdev In order to run your empty application, type: $ cd testing_app $ flutter run Your empty application code is in testing_app/lib/main.dart.
Thêm phần phụ thuộc của nhà xuất bản vào dòng lệnh.
provider
để dễ dàng quản lý trạng thái,integration_test
để kiểm thử tự chạy mã Flutter trên các thiết bị và trình mô phỏng,flutter_driver
để sử dụng một API nâng cao giúp kiểm thử các ứng dụng Flutter chạy trên trình mô phỏng và thiết bị thực,test
cho công cụ kiểm thử chung,go_router
để xử lý hoạt động điều hướng trong ứng dụng.
$ cd testing_app $ flutter pub add provider go_router dev:test 'dev:flutter_driver:{"sdk":"flutter"}' 'dev:integration_test:{"sdk":"flutter"}' Resolving dependencies... Downloading packages... + _fe_analyzer_shared 67.0.0 (68.0.0 available) + analyzer 6.4.1 (6.5.0 available) + args 2.5.0 + convert 3.1.1 + coverage 1.7.2 + crypto 3.0.3 + file 7.0.0 + flutter_driver 0.0.0 from sdk flutter + flutter_web_plugins 0.0.0 from sdk flutter + frontend_server_client 4.0.0 + fuchsia_remote_debug_protocol 0.0.0 from sdk flutter + glob 2.1.2 + go_router 14.0.2 + http_multi_server 3.2.1 + http_parser 4.0.2 + integration_test 0.0.0 from sdk flutter + io 1.0.4 + js 0.7.1 leak_tracker 10.0.4 (10.0.5 available) leak_tracker_flutter_testing 3.0.3 (3.0.5 available) + logging 1.2.0 material_color_utilities 0.8.0 (0.11.1 available) meta 1.12.0 (1.14.0 available) + mime 1.0.5 + nested 1.0.0 + node_preamble 2.0.2 + package_config 2.1.0 + platform 3.1.4 + pool 1.5.1 + process 5.0.2 + provider 6.1.2 + pub_semver 2.1.4 + shelf 1.4.1 + shelf_packages_handler 3.0.2 + shelf_static 1.1.2 + shelf_web_socket 1.0.4 + source_map_stack_trace 2.1.1 + source_maps 0.10.12 + sync_http 0.3.1 + test 1.25.2 (1.25.4 available) test_api 0.7.0 (0.7.1 available) + test_core 0.6.0 (0.6.2 available) + typed_data 1.3.2 + watcher 1.1.0 + web 0.5.1 + web_socket_channel 2.4.5 + webdriver 3.0.3 + webkit_inspection_protocol 1.2.1 + yaml 3.1.2 Changed 44 dependencies! 9 packages have newer versions incompatible with dependency constraints. Try `flutter pub outdated` for more information.
Bạn phải thêm các phần phụ thuộc sau đây vào pubspec.yaml:
pubspec.yaml
name: testing_app description: "A new Flutter project." publish_to: 'none' version: 0.1.0 environment: sdk: '>=3.4.0-0 <4.0.0' dependencies: flutter: sdk: flutter go_router: ^14.0.2 provider: ^6.1.2 dev_dependencies: flutter_test: sdk: flutter flutter_lints: ^3.0.0 test: ^1.25.2 flutter_driver: sdk: flutter integration_test: sdk: flutter flutter: uses-material-design: true
Mở dự án trong trình soạn thảo mã mà bạn chọn rồi chạy ứng dụng. Ngoài ra, hãy chạy trên dòng lệnh như sau.
$ flutter run
4. Xây dựng ứng dụng
Tiếp theo, bạn sẽ xây dựng ứng dụng để có thể kiểm thử. Ứng dụng này chứa các tệp sau:
lib/models/favorites.dart
– tạo lớp mô hình cho danh sách yêu thíchlib/screens/favorites.dart
– tạo bố cục cho danh sách yêu thíchlib/screens/home.dart
– tạo một danh sách các mụclib/main.dart
– tệp chính nơi ứng dụng khởi động
Trước tiên, hãy tạo mô hình Favorites
trong lib/models/favorites.dart
Tạo một thư mục mới có tên models
trong thư mục lib
, sau đó tạo một tệp mới có tên favorites.dart
. Trong tệp đó, hãy thêm mã sau:
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();
}
}
Thêm trang Mục yêu thích trong lib/screens/favorites.dart
Tạo một thư mục mới có tên screens
trong thư mục lib
và trong thư mục đó, hãy tạo một tệp mới có tên favorites.dart
. Trong tệp đó, hãy thêm mã sau:
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),
),
);
},
),
),
);
}
}
Thêm Trang chủ trong lib/screens/home.dart
Trong thư mục lib/screens
, hãy tạo một tệp mới khác có tên home.dart
. Trong lib/screens/home.dart
, hãy thêm mã sau:
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),
),
);
},
),
),
);
}
}
Thay thế nội dung của lib/main.dart
Thay thế nội dung của lib/main.dart
bằng mã sau:
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(
colorScheme: ColorScheme.fromSeed(
seedColor: Colors.deepPurple,
),
useMaterial3: true,
),
routerConfig: _router,
),
);
}
}
Ứng dụng hiện đã hoàn thiện, nhưng chưa được kiểm thử.
Chạy ứng dụng. Giao diện sẽ giống như ảnh chụp màn hình sau:
Ứng dụng hiển thị một danh sách các mục. Nhấn vào biểu tượng hình trái tim trên hàng bất kỳ để điền hình trái tim và thêm mặt hàng vào danh sách yêu thích. Nút Yêu thích trên AppBar
sẽ đưa bạn đến màn hình thứ hai chứa danh sách yêu thích.
Ứng dụng hiện đã sẵn sàng để thử nghiệm. Bạn sẽ bắt đầu kiểm thử ứng dụng trong bước tiếp theo.
5. Kiểm thử đơn vị nhà cung cấp
Bạn sẽ bắt đầu bằng cách kiểm thử đơn vị mô hình favorites
. Kiểm thử đơn vị là gì? Kiểm thử đơn vị xác minh rằng mọi đơn vị phần mềm riêng lẻ, cho dù đó là một chức năng, đối tượng hay tiện ích, đều thực hiện đúng tác vụ dự định của nó.
Ngoại trừ các bài kiểm thử tích hợp, tất cả tệp kiểm thử trong một ứng dụng Flutter đều được đặt trong thư mục test
.
Xoá test/widget_test.dart
Trước khi bạn bắt đầu thử nghiệm, hãy xoá tệp widget_test.dart
. Bạn sẽ thêm các tệp kiểm thử của riêng mình.
Tạo tệp thử nghiệm mới
Trước tiên, bạn sẽ kiểm thử phương thức add()
trong mô hình Favorites
để xác minh một mục mới được thêm vào danh sách và danh sách này phản ánh thay đổi. Theo quy ước, cấu trúc thư mục trong thư mục test
giống với cấu trúc trong thư mục lib
và các tệp Dart có cùng tên với _test
được nối thêm.
Tạo thư mục models
trong thư mục test
. Trong thư mục mới này, hãy tạo một tệp favorites_test.dart
có nội dung sau:
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);
});
});
}
Khung kiểm thử Flutter cho phép bạn liên kết các chương trình kiểm thử tương tự liên quan với nhau trong một nhóm. Có thể có nhiều nhóm trong một tệp kiểm thử duy nhất nhằm kiểm thử nhiều phần của tệp tương ứng trong thư mục lib
.
Phương thức test()
nhận 2 tham số vị trí: description
của chương trình kiểm thử và callback
nơi bạn thực sự viết chương trình kiểm thử.
Kiểm thử việc xoá một mục khỏi danh sách. Chèn chương trình kiểm thử sau vào cùng một nhóm 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);
});
Chạy công cụ kiểm tra
Tại dòng lệnh, hãy chuyển đến thư mục gốc của dự án và nhập lệnh sau:
$ flutter test test/models/favorites_test.dart
Nếu mọi thứ đều hoạt động, bạn sẽ thấy một thông báo tương tự như sau:
00:06 +2: All tests passed!
Tệp thử nghiệm hoàn chỉnh: test/models/favorites_test.dart
.
Để biết thêm thông tin về kiểm thử đơn vị, hãy xem Giới thiệu về kiểm thử đơn vị.
6. Kiểm thử tiện ích
Ở bước này, bạn sẽ thêm mã để kiểm thử các tiện ích. Tính năng kiểm thử tiện ích là chỉ dành cho Flutter, ở đó bạn có thể kiểm thử từng tiện ích theo một cách riêng biệt. Bước này sẽ kiểm thử từng màn hình HomePage
và FavoritesPage
.
Tính năng kiểm thử tiện ích sử dụng hàm testWidget()
thay vì hàm test()
. Giống như hàm test()
, hàm testWidget()
nhận 2 tham số: description,
và callback
. Tuy nhiên, lệnh gọi lại sẽ lấy WidgetTester
làm đối số.
Kiểm thử tiện ích sử dụng TestFlutterWidgetsBinding
, một lớp cung cấp tài nguyên cho các tiện ích mà chúng sẽ có trong một ứng dụng đang chạy, ví dụ: thông tin về kích thước màn hình, khả năng lên lịch ảnh động, nhưng không cần chạy bên trong ứng dụng. Thay vào đó, một môi trường ảo sẽ được dùng để tạo thực thể cho tiện ích này, rồi chạy kiểm thử kết quả. Tại đây, pumpWidget
sẽ bắt đầu quy trình này bằng cách yêu cầu khung gắn kết và đo lường một tiện ích cụ thể giống như trong ứng dụng.
Khung kiểm thử tiện ích cung cấp trình tìm kiếm để tìm các tiện ích, ví dụ: text()
, byType()
và byIcon().
. Khung này cũng cung cấp trình so khớp để xác minh kết quả.
Hãy bắt đầu bằng cách kiểm thử tiện ích HomePage
.
Tạo tệp thử nghiệm mới
Lần kiểm thử đầu tiên xác minh xem thao tác cuộn HomePage
có hoạt động đúng cách hay không.
Tạo một tệp mới trong thư mục test
rồi đặt tên cho tệp đó là home_test.dart
. Trong tệp mới tạo, hãy thêm mã sau:
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: 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);
});
});
}
Hàm createHomeScreen()
dùng để tạo một ứng dụng tải tiện ích cần kiểm thử trong MaterialApp, được gói vào một ChangeNotifierProvider. Tiện ích Trang chủ cần cả hai tiện ích này đều xuất hiện phía trên nó trong cây tiện ích để tiện ích có thể kế thừa từ tiện ích và nhận được quyền truy cập vào dữ liệu mà tiện ích cung cấp. Hàm này được truyền dưới dạng tham số vào hàm pumpWidget()
.
Tiếp theo, hãy kiểm thử xem khung có thể tìm thấy ListView
được kết xuất trên màn hình hay không.
Thêm đoạn mã sau vào 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),
const Offset(0, -200),
3000,
);
await tester.pumpAndSettle();
expect(find.text('Item 0'), findsNothing);
});
});
Chạy công cụ kiểm tra
Trước tiên, hãy chạy kiểm thử giống như cách bạn chạy kiểm thử đơn vị, bằng lệnh:
$ flutter test test/home_test.dart
Chương trình kiểm thử sẽ chạy nhanh và bạn sẽ thấy một thông báo như sau:
00:02 +2: All tests passed!
Bạn cũng có thể chạy kiểm thử tiện ích bằng một thiết bị hoặc trình mô phỏng để có thể xem quá trình kiểm thử đang diễn ra. Tính năng này cũng cho phép bạn sử dụng tính năng khởi động nóng.
Cắm thiết bị vào hoặc khởi động trình mô phỏng. Bạn cũng có thể chạy bài kiểm thử dưới dạng một ứng dụng dành cho máy tính.
Từ dòng lệnh, hãy chuyển đến thư mục gốc của dự án và nhập lệnh sau:
$ flutter run test/home_test.dart
Có thể bạn sẽ phải chọn thiết bị để chạy kiểm thử. Trong trường hợp đó, hãy làm theo hướng dẫn và chọn một thiết bị:
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"):
Nếu mọi thứ đều hoạt động, bạn sẽ thấy kết quả tương tự như sau:
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!
Tiếp theo, bạn sẽ thực hiện các thay đổi đối với tệp kiểm thử và nhấn Shift + R
để khởi động lại ứng dụng và chạy lại mọi bài kiểm thử. Đừng dừng ứng dụng.
Thêm nhiều thử nghiệm hơn vào nhóm thử nghiệm tiện ích Trang chủ. Sao chép mã kiểm thử sau vào tệp:
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(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);
});
Kiểm thử này xác minh rằng thao tác nhấn vào IconButton
sẽ thay đổi từ Icons.favorite_border
(một trái tim mở) thành Icons.favorite
(một trái tim đã điền) và quay trở lại Icons.favorite_border
khi được nhấn lại.
Nhập Shift + R
. Thao tác nóng này sẽ khởi động lại ứng dụng và chạy lại tất cả các bài kiểm thử.
Tệp thử nghiệm hoàn chỉnh: test/home_test.dart
.
Sử dụng quy trình tương tự để kiểm thử FavoritesPage
bằng mã sau. Làm theo các bước tương tự và chạy quy trình đó.
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';
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);
});
});
}
Quy trình kiểm thử này xác minh xem một mục có biến mất khi nhấn nút đóng (xoá) hay không.
Để biết thêm thông tin về kiểm thử tiện ích, hãy truy cập:
7. Kiểm thử giao diện người dùng ứng dụng bằng các bài kiểm thử tích hợp
Kiểm thử tích hợp được dùng để kiểm thử cách các thành phần riêng lẻ của ứng dụng hoạt động cùng nhau trên tổng thể. Thư viện integration_test
được dùng để thực hiện kiểm thử tích hợp trong Flutter. Đây là phiên bản Selenium WebDriver, Protractor, Espresso hoặc Earl Gray của Flutter. Gói này sử dụng flutter_driver
nội bộ để lái thử nghiệm trên một thiết bị.
Việc viết chương trình kiểm thử tích hợp trong Flutter tương tự như việc viết chương trình kiểm thử tiện ích, ngoại trừ việc các chương trình kiểm thử tích hợp chạy trên một thiết bị di động, trình duyệt hoặc ứng dụng dành cho máy tính, được gọi là thiết bị mục tiêu.
Viết thử nghiệm
Tạo thư mục có tên integration_test
trong thư mục gốc của dự án, sau đó tạo một tệp mới có tên app_test.dart
trong thư mục đó.
integration_test/app_test.dart
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);
}
});
});
}
Chạy công cụ kiểm tra
Cắm thiết bị vào hoặc khởi động trình mô phỏng. Bạn cũng có thể chạy bài kiểm thử dưới dạng một ứng dụng dành cho máy tính.
Tại dòng lệnh, hãy chuyển đến thư mục gốc của dự án và nhập lệnh sau:
$ flutter test integration_test/app_test.dart
Nếu mọi thứ đều hoạt động, bạn sẽ thấy kết quả tương tự như sau:
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. Kiểm thử hiệu suất của ứng dụng bằng Trình điều khiển Flutter
Viết bài kiểm thử hiệu suất
Tạo một tệp kiểm thử mới có tên perf_test.dart trong thư mục Integration_test với nội dung sau:
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');
});
});
}
Hàm ensureInitialized()
xác minh xem trình điều khiển kiểm thử tích hợp có được khởi tạo hay không và khởi động lại nếu cần. Bạn nên đặt framePolicy
thành fullyLive
để kiểm thử mã ảnh động.
Chương trình kiểm thử này sẽ cuộn qua danh sách các mục rất nhanh rồi cuộn lên trên. Hàm traceAction()
ghi lại các thao tác và tạo một bản tóm tắt tiến trình.
Nhận kết quả hiệu suất
Để thu được kết quả, hãy tạo thư mục có tên test_driver
với tệp có tên perf_driver.dart
và thêm đoạn mã sau:
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,
);
}
},
);
}
Chạy công cụ kiểm tra
Cắm thiết bị vào hoặc khởi động trình mô phỏng.
Tại dòng lệnh, hãy chuyển đến thư mục gốc của dự án và nhập lệnh sau:
$ flutter drive \
--driver=test_driver/perf_driver.dart \
--target=integration_test/perf_test.dart \
--profile \
--no-dds
Nếu mọi thứ đều hoạt động, bạn sẽ thấy kết quả tương tự như sau:
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.
Sau khi kiểm thử hoàn tất thành công, thư mục bản dựng ở gốc của dự án sẽ chứa hai tệp:
scrolling_summary.timeline_summary.json
chứa phần tóm tắt. Mở tệp bằng bất kỳ trình chỉnh sửa văn bản nào để xem lại thông tin chứa trong tệp đó.scrolling_summary.timeline.json
chứa dữ liệu dòng thời gian đầy đủ.
Để biết thêm thông tin về quy trình kiểm thử quá trình tích hợp, hãy truy cập vào:
9. Xin chúc mừng!
Bạn đã hoàn thành lớp học lập trình và học nhiều cách kiểm thử ứng dụng Flutter.
Kiến thức bạn học được
- Cách kiểm thử nhà cung cấp với sự trợ giúp của kiểm thử đơn vị
- Cách kiểm thử tiện ích bằng khung kiểm thử tiện ích
- Cách kiểm thử giao diện người dùng của ứng dụng bằng các bài kiểm thử tích hợp
- Cách kiểm thử hiệu suất của ứng dụng bằng các bài kiểm thử tích hợp
Để tìm hiểu thêm về cách thử nghiệm trong Flutter, hãy truy cập vào