Nguyễn Đình Cường
0 comment
09 Nov, 2026
Sửa một chỗ làm hỏng chỗ khác là cơn ác mộng quen thuộc của ứng dụng lớn dần. Kiểm thử tự động giúp bạn tự tin thay đổi mã. Flutter hỗ trợ ba tầng kiểm thử: unit test, widget test và integration test. Bài này giới thiệu từng loại cùng ví dụ.
Nên có nhiều bài kiểm thử nhỏ, nhanh ở đáy và ít bài lớn, chậm ở đỉnh:
Giả sử có một hàm tính tổng giỏ hàng:
// lib/cart.dart
class CartItem {
final String name;
final int price;
final int qty;
const CartItem(this.name, this.price, this.qty);
}
int cartTotal(List<CartItem> items) =>
items.fold(0, (sum, i) => sum + i.price * i.qty);
// test/cart_test.dart
import 'package:flutter_test/flutter_test.dart';
import 'package:my_app/cart.dart';
void main() {
group('cartTotal', () {
test('giỏ rỗng có tổng bằng 0', () {
expect(cartTotal([]), 0);
});
test('tính đúng tổng nhiều mặt hàng', () {
final items = [
const CartItem('A', 10000, 2),
const CartItem('B', 5000, 1),
];
expect(cartTotal(items), 25000);
});
});
}
Chạy bằng lệnh flutter test. Đặt tên bài kiểm thử mô tả hành vi mong đợi để khi lỗi, bạn đọc tên là hiểu vấn đề.
Kiểm thử một bộ đếm: bấm nút thì số tăng lên.
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:my_app/counter_page.dart';
void main() {
testWidgets('bấm nút tăng bộ đếm', (WidgetTester tester) async {
await tester.pumpWidget(const MaterialApp(home: CounterPage()));
expect(find.text('Đã bấm 0 lần'), findsOneWidget);
await tester.tap(find.byIcon(Icons.add));
await tester.pump();
expect(find.text('Đã bấm 1 lần'), findsOneWidget);
});
}
Các hàm quan trọng: find để tìm widget, tap và enterText để mô phỏng thao tác, pump để vẽ lại sau thay đổi, pumpAndSettle để chờ hoạt ảnh xong.
Kiểm thử không nên gọi mạng thật. Hãy tách phần truy cập dữ liệu sau một giao diện và cung cấp bản giả:
abstract class UserRepository {
Future<String> fetchName();
}
class FakeUserRepository implements UserRepository {
@override
Future<String> fetchName() async => 'Bem';
}
Truyền bản giả vào widget hoặc qua hệ thống tiêm phụ thuộc trong bài kiểm thử. Thư viện như mocktail giúp tạo đối tượng giả nhanh và kiểm tra xem hàm có được gọi đúng không.
Gói integration_test cho phép viết kịch bản chạy trên thiết bị:
import 'package:integration_test/integration_test.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:my_app/main.dart' as app;
void main() {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
testWidgets('đăng nhập rồi thấy trang chủ', (tester) async {
app.main();
await tester.pumpAndSettle();
await tester.enterText(find.byKey(const Key('email')), 'a@b.com');
await tester.enterText(find.byKey(const Key('password')), '123456');
await tester.tap(find.byKey(const Key('login_button')));
await tester.pumpAndSettle();
expect(find.text('Trang chủ'), findsOneWidget);
});
}
Chạy bằng flutter test integration_test với thiết bị đang kết nối. Loại này chậm, nên chỉ dùng cho các luồng quan trọng như đăng nhập, thanh toán.
Độ phủ mã cao không có nghĩa là chất lượng cao. Tập trung kiểm thử phần logic quan trọng, dễ lỗi và khó thấy bằng mắt thường, thay vì cố đạt một con số.
Bắt đầu với unit test cho logic, thêm widget test cho các thành phần chính và vài integration test cho luồng cốt lõi. Dần dần bạn sẽ thấy việc thay đổi code bớt đáng sợ hơn nhiều.
Ngoài ba loại trên, Flutter hỗ trợ golden test: so sánh ảnh chụp của widget với ảnh chuẩn đã lưu để phát hiện thay đổi giao diện ngoài ý muốn. Loại này hữu ích cho các thành phần dùng chung như nút hay thẻ. Hạn chế là ảnh có thể khác nhau chút ít giữa các nền tảng và phiên bản, nên cần cố định môi trường chạy trong quy trình tự động. Hãy dùng có chọn lọc cho những widget quan trọng, đừng áp dụng cho mọi màn hình vì chi phí bảo trì ảnh chuẩn khá cao.
Hãy đặt tệp kiểm thử phản chiếu cấu trúc thư mục lib, với hậu tố _test, để ai cũng tìm được bài kiểm thử tương ứng. Tách các hàm tạo dữ liệu mẫu và đối tượng giả vào thư mục dùng chung để tránh lặp lại. Chạy toàn bộ kiểm thử trước mỗi lần gộp mã và đặt tiêu chí không gộp khi kiểm thử đỏ.
Để học cách xây dựng ứng dụng có kiểm thử từ đầu, bạn có thể xem các khóa học tại codebem.com.
Nguyễn Đình Cường
0 comment