Lập trình Flutter - Testing

Testing là một phần rất quan trọng trong việc phát triển vòng đời của một ứng dụng. Nó đảm bảo rằng ứng dụng sẽ tốt hơn và chất lượng cao hơn.Testing yêu cầu có kế hoạch và thực thi cẩn thận . Nó cũng tiêu tốn nhiều thời gian nhất trong việc lập trình

Dart và Flutter framework cung cấp gói mở rộng để hỗ trợ trong việc testing tự động của ứng dụng

 Một số dạng Testing

Thông thường, có 3 loại testing 

Unit Testing

Là phương pháp testing đơn giản nhất . Nó dựa trên việc đảm bảo độ chính xác của một đoạn code . Nhưng nó hoạt động không thực sự tốt trên môi trường thật nên nó ít được sử dụng trong việc tìm lỗi 

Widget Testing

Được dựa trên việc đảm bảo độ chính xác trong việc tạo, render hay tương tác của widget với widget khác như mong đợi. Nó hoạt động từng bước và cung cấp gần như thời gian thực trong việc tìm lỗi

Integration Testing

Integration testing bao gồm cả hai unit testing và widget testing cùng với các thành phần bên ngoài ứng dụng như database, web service, .. Nó mô phỏng hoặc giả lập môi trường thực để tìm ra gần như tất cả các lỗi . Vì thế nó là quá trình phức tạp nhất của ưng dụng 

Flutter cung cấp, hỗ trợ tất cả các loại testing. Nó cung cấp gói mở rộng và hỗ trợ riêng cho Widget testing. Trong bài này, chúng ta sẽ tập trung bàn luận chi tiết về widget testing

Widget Testing

Flutter testing framework cung cấp phương thúc testWidgets để test widgets. Nó chấp nhận 2 tham số 

- Test decription

- Test code 

testWidgets('test description: find a widget', '<test code>')
Các bước thực hiện 

Widget Testing thực hiện 3 bước khác biệt như sau :

- Render widget trong môi trường testing

- WidgetTester là lớp cung cấp bởi Flutter testing framework để build và render widget. Phương thức pumpWidget của lớp WidgetTester chấp nhận bất kì Widget và render nó trong môi trường testing

testWidgets('finds a specific instance', (WidgetTester tester) async { 
   await tester.pumpWidget(MaterialApp( 
      home: Scaffold( 
         body: Text('Hello'), 
      ), 
   )); 
});

Tìm đến widget mà chúng ta cần test

- Flutter framework cung cấp nhiều tính năng để tìm đến widget render trong môi trường testing và gọi chung là Finders.Chúng ta hầu như thường xuyên sử dụng sử dụng finders là find.text, find.byKey và find.byWidget

  1. find.text để tìm widget mà chứa đoạn text cụ thể - find.text('Hello')
  2. find.byKey để tìm widget chứa các key cụ thể - find.byKey('home')
  3. find.byWidget để tìm wiget theo biến thể của nó -find.byWidget (homeWidget)

- Đảm bảo các widget làm việc như mong đợi

- Flutter framework cung cấp nhiều tính năng để  phù hợp widget với widget dự kiến và gọi là Matchers. Một vài điều quan trọng về matchers như sau :

findsOneWidget - Xác minh widget duy nhất được tìm thấy

expect(find.text('Hello'), findsOneWidget);

findsNothing - Xác minh không wiget nào được tìm thấy

expect(find.text('Hello World'), findsNothing);

findsWidgets − Xác minh nhiều hơn một wiget được tìm thấy 

expect(find.text('Save'), findsWidgets);

findsNWidgets - Xác minh N widget tìm thấy 

expect(find.text('Save'), findsNWidgets(2));

Đoạn code ví dụ như sau :

testWidgets('finds hello widget', (WidgetTester tester) async { 
   await tester.pumpWidget(MaterialApp( 
      home: Scaffold( 
         body: Text('Hello'), 
      ), 
   )); 
   expect(find.text('Hello'), findsOneWidget); 
});

Ở trên, chúng ta render một widget MaterialApp tới dòng text Hello sử dụng Text widget. Sau đó , ta sử dụng find.text để tìm widget và khớp nó bằng cách sử dụng findsOneWidget

 Ví dụ cụ thể

Ta sẽ tạo nhanh ứng dụng flutter và viết widget test để hiểu hơn các bước về ý tưởng với tên  flutter_test_app

Mở widget_test.dart trong thư mục . 

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); 
});

Ở đây, test code có chức năng như sau :

- Renders MyApp widget sử dụng tester.pumpWidget

- Đảm bảo rằng bộ đếm ban đầu bằng 0 sử dụng findsOneWidget và findsOneWidget 

- Tìm nút tăng bộ đếm sử dụng phương thức tester.tap

- Đảm bảo rằng bộ đếm được tăng lên bằng cách sử dụng findsOneWidget và findsNothing

Ta hãy thử nhấn vào nút tăng bộ đếm và sau đó kiểm tra liệu bộ đếm có tăng lên là 2 

await tester.tap(find.byIcon(Icons.add)); 
await tester.pump(); 

expect(find.text('2'), findsOneWidget);

Nhấn Run menu 

Nhấn test trong widget_test.dart . Nó sẽ chạy và hiển thị kết quả trong cửa sổ kết quả