Widget Testing
ใน React คุณทดสอบ components ด้วย jest และ React Testing Library: render() mount component, screen.getByText() ใช้ query, fireEvent.click() ใช้โต้ตอบ Testing API ของ Flutter แมปแทบหนึ่งต่อหนึ่ง: testWidgets() คือ block test() ของคุณ, pumpWidget() คือ render(), find.text() คือ screen.getByText(), และ tester.tap() คือ fireEvent.click() mental model เหมือนกันทุกประการ — แค่ syntax ต่างกัน
หมายเหตุเกี่ยวกับการทดสอบ: Widget tests ต้องใช้ runner ของ
flutter test— ไม่สามารถรันใน DartPad ได้ รันในเครื่องด้วยflutter test
การตั้งค่าทดสอบ
หัวข้อที่มีชื่อว่า “การตั้งค่าทดสอบ”Flutter tests อยู่ใน test/ ที่ root ของโปรเจกต์ ซึ่งสอดคล้องกับวิธีที่คุณอาจวาง tests ไว้ใน src/__tests__/ หรือ colocate ไฟล์ *.test.tsx naming convention คือ *_test.dart — test runner ของ Flutter จะค้นหาไฟล์ที่ลงท้ายด้วย _test.dart ใน test/ โดยอัตโนมัติ
รัน tests ด้วย:
# Run all testsflutter test
# Run a single fileflutter test test/counter_test.dartpackage flutter_test ฝังอยู่ใน SDK แล้ว — ไม่ต้องใช้ npm install นำเข้าในทุกไฟล์ทดสอบ:
import 'package:flutter_test/flutter_test.dart';ห่อ widget ที่ทดสอบด้วย MaterialApp(home: Scaffold(body: ...)) นี่คือ Flutter equivalent ของการห่อ component ใน Provider, ThemeProvider, หรือ custom render wrapper ใน RTL — wrapper นี้ทำให้ widget ที่อ่าน Theme, MediaQuery, หรือ Navigator จาก ancestor context ทำงานได้
การแมป Core API
หัวข้อที่มีชื่อว่า “การแมป Core API”| React Testing Library | Flutter widget test | วัตถุประสงค์ |
|---|---|---|
render(<MyWidget />) | await tester.pumpWidget(const MaterialApp(home: MyWidget())) | Mount widget |
screen.getByText('Hi') | find.text('Hi') | ค้นหาด้วย text |
screen.getByType(Button) | find.byType(ElevatedButton) | ค้นหาด้วย type |
screen.getByKey('my-key') | find.byKey(const Key('my-key')) | ค้นหาด้วย key |
fireEvent.click(el) | await tester.tap(find.byType(ElevatedButton)) | Tap |
userEvent.type(el, 'Hello') | await tester.enterText(find.byType(TextField), 'Hello') | พิมพ์ text |
await waitFor(...) | await tester.pumpAndSettle() | รอ animations/async |
expect(el).toBeInTheDocument() | expect(find.text('Hi'), findsOneWidget) | ยืนยันการมีอยู่ |
expect(el).not.toBeInTheDocument() | expect(find.text('Hi'), findsNothing) | ยืนยันการไม่มีอยู่ |
// React + React Testing Libraryimport { render, screen, fireEvent } from '@testing-library/react';import Counter from './Counter';
test('increments count on button click', () => { render(<Counter />);
expect(screen.getByText('Count: 0')).toBeInTheDocument();
fireEvent.click(screen.getByRole('button', { name: /increment/i }));
expect(screen.getByText('Count: 1')).toBeInTheDocument();});// Flutter testWidgetsimport 'package:flutter/material.dart';import 'package:flutter_test/flutter_test.dart';import 'package:my_app/counter.dart';
void main() { testWidgets('increments count on button tap', (WidgetTester tester) async { await tester.pumpWidget( const MaterialApp(home: Scaffold(body: Counter())), );
expect(find.text('Count: 0'), findsOneWidget);
await tester.tap(find.byType(ElevatedButton)); await tester.pump();
expect(find.text('Count: 1'), findsOneWidget); });}