اختبار التطبيقات — Flutter المتقدم
اختبار تطبيقات Flutter
أنواع الاختبارات
1. Unit Tests: اختبار الدوال والـ Classes
2. Widget Tests: اختبار المكونات
3. Integration Tests: اختبار التطبيق كاملاً
1. Unit Tests
// lib/services/calculator.dart
class Calculator {
int add(int a, int b) => a + b;
int subtract(int a, int b) => a - b;
int multiply(int a, int b) => a * b;
double divide(int a, int b) {
if (b == 0) throw ArgumentError('Cannot divide by zero');
return a / b;
}
}
// test/calculator_test.dart
import 'package:test/test.dart';
import 'package:my_app/services/calculator.dart';
void main() {
group('Calculator', () {
late Calculator calculator;
setUp(() {
calculator = Calculator();
});
test('should add two numbers', () {
expect(calculator.add(2, 3), equals(5));
});
test('should subtract two numbers', () {
expect(calculator.subtract(5, 3), equals(2));
});
test('should multiply two numbers', () {
expect(calculator.multiply(3, 4), equals(12));
});
test('should divide two numbers', () {
expect(calculator.divide(10, 2), equals(5.0));
});
test('should throw error when dividing by zero', () {
expect(
() => calculator.divide(10, 0),
throwsA(isA<ArgumentError>()),
);
});
});
}2. Widget Tests
// test/widgets/counter_test.dart
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:my_app/screens/counter_screen.dart';
void main() {
testWidgets('Counter increments', (WidgetTester tester) async {
// Build widget
await tester.pumpWidget(MaterialApp(home: CounterScreen()));
// Verify initial state
expect(find.text('0'), findsOneWidget);
expect(find.text('1'), findsNothing);
// Tap the button
await tester.tap(find.byIcon(Icons.add));
await tester.pump(); // Rebuild
// Verify state changed
expect(find.text('0'), findsNothing);
expect(find.text('1'), findsOneWidget);
});
testWidgets('Counter decrements', (WidgetTester tester) async {
await tester.pumpWidget(MaterialApp(home: CounterScreen()));
// Tap increment first
await tester.tap(find.byIcon(Icons.add));
await tester.pump();
// Then decrement
await tester.tap(find.byIcon(Icons.remove));
await tester.pump();
expect(find.text('0'), findsOneWidget);
});
}3. Testing with Mocks
dev_dependencies:
mockito: ^5.4.0
build_runner: ^2.4.0import 'package:mockito/annotations.dart';
import 'package:mockito/mockito.dart';
import 'api_service.dart';
@GenerateMocks([ApiService])
import 'user_repository_test.mocks.dart';
void main() {
late MockApiService mockApi;
late UserRepository repository;
setUp(() {
mockApi = MockApiService();
repository = UserRepository(mockApi);
});
test('should return users from API', () async {
// Arrange
final users = [User(id: 1, name: 'Test')];
when(mockApi.getUsers()).thenAnswer((_) async => users);
// Act
final result = await repository.getUsers();
// Assert
expect(result, equals(users));
verify(mockApi.getUsers()).called(1);
});
test('should throw when API fails', () async {
when(mockApi.getUsers()).thenThrow(Exception('Network error'));
expect(
() => repository.getUsers(),
throwsA(isA<Exception>()),
);
});
}4. تشغيل الاختبارات
# كل الاختبارات
flutter test
# ملف محدد
flutter test test/calculator_test.dart
# مع تغطية الكود
flutter test --coverageاختبر فهمك