0% found this document useful (0 votes)
21 views20 pages

Flutter Testing Techniques Explained

The Complete Flutter Testing Guide covers essential testing concepts including unit, widget, and integration tests, emphasizing their importance for catching bugs, ensuring code quality, and providing documentation. It includes practical examples, best practices, and common interview questions related to Flutter testing. The guide also highlights the use of mocking dependencies and the significance of test coverage in maintaining robust applications.

Uploaded by

omkar.wangane
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
21 views20 pages

Flutter Testing Techniques Explained

The Complete Flutter Testing Guide covers essential testing concepts including unit, widget, and integration tests, emphasizing their importance for catching bugs, ensuring code quality, and providing documentation. It includes practical examples, best practices, and common interview questions related to Flutter testing. The guide also highlights the use of mocking dependencies and the significance of test coverage in maintaining robust applications.

Uploaded by

omkar.wangane
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd

Complete Flutter Testing Guide

Table of Contents
1. Testing Fundamentals
2. Unit Tests
3. Widget Tests
4. Integration Tests
5. Best Practices
6. Common Interview Questions

Testing Fundamentals
Why Testing Matters
Catch bugs early: Find issues before users do
Refactoring confidence: Change code without breaking functionality
Documentation: Tests show how code should work
Code quality: Forces you to write testable, modular code

Testing Pyramid

/\
/ \ Integration Tests (Few - Slow, Expensive)
/____\
/ \
/ Widget \ Widget Tests (Some - Medium speed)
/ Tests \
/___________\
/ \
/ Unit Tests \ Unit Tests (Many - Fast, Cheap)
/_______________\

Setup

Add to [Link]:

yaml
dev_dependencies:
flutter_test:
sdk: flutter
mockito: ^5.4.0
build_runner: ^2.4.0
integration_test:
sdk: flutter

Unit Tests
What are Unit Tests?

Tests for individual functions, methods, or classes in isolation. They're fast and test business logic.

File Structure

lib/
models/
[Link]
services/
api_service.dart
test/
models/
user_test.dart
services/
api_service_test.dart

Basic Unit Test Example

dart
// lib/models/[Link]
class Calculator {
int add(int a, int b) => a + b;
int subtract(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/models/calculator_test.dart
import 'package:flutter_test/flutter_test.dart';
import 'package:your_app/models/[Link]';

void main() {
// Test suite
group('Calculator', () {
late Calculator calculator;

// Runs before each test


setUp(() {
calculator = Calculator();
} );

// Individual test
test('should add two numbers correctly', () {
// Arrange
final a = 5;
final b = 3;

// Act
final result = [Link](a, b);

// Assert
expect(result, 8);
} );

test('should subtract two numbers correctly', () {


expect([Link](10, 4), 6);
} );

test('should throw error when dividing by zero', () {


expect(
() => [Link](10, 0),
throwsA(isA<ArgumentError>()),
);
} );
} );
}

Mocking Dependencies

dart
// lib/services/user_service.dart
class UserService {
final ApiClient apiClient;

UserService([Link]);

Future<User> getUser(String id) async {


final response = await [Link]('/users/$id');
return [Link](response);
}
}

// test/services/user_service_test.dart
import 'package:mockito/[Link]';
import 'package:mockito/[Link]';
import 'package:flutter_test/flutter_test.dart';

// Generate mock
@GenerateMocks([ApiClient])
import 'user_service_test.[Link]';

void main() {
group('UserService', () {
late UserService userService;
late MockApiClient mockApiClient;

setUp(() {
mockApiClient = MockApiClient();
userService = UserService(mockApiClient);
} );

test('should fetch user successfully', () async {


// Arrange
final mockResponse = {'id': '1', 'name': 'John'};
when([Link]('/users/1'))
.thenAnswer((_) async => mockResponse);

// Act
final user = await [Link]('1');

// Assert
expect([Link], 'John');
verify([Link]('/users/1')).called(1);
} );
} );
}

Common Matchers

dart

expect(actual, expected); // Equals


expect(actual, isNull); // Null check
expect(actual, isNotNull); // Not null
expect(actual, isTrue); // Boolean
expect(actual, greaterThan(5)); // Comparison
expect(actual, contains('text')); // String/List contains
expect(() => func(), throwsException); // Throws exception
expect(actual, isA<Type>()); // Type check

Widget Tests
What are Widget Tests?

Tests for UI components in isolation. They test how widgets look and behave without running the full app.

Basic Widget Test

dart
// lib/widgets/counter_widget.dart
class CounterWidget extends StatefulWidget {
@override
_CounterWidgetState createState() => _CounterWidgetState();
}

class _CounterWidgetState extends State<CounterWidget> {


int _counter = 0;

void _increment() {
setState(() {
_counter++;
} );
}

@override
Widget build(BuildContext context) {
return Column(
children: [
Text('Count: $_counter', key: Key('counter_text')),
ElevatedButton(
key: Key('increment_button'),
onPressed: _increment,
child: Text('Increment'),
),
],
);
}
}

// test/widgets/counter_widget_test.dart
import 'package:flutter/[Link]';
import 'package:flutter_test/flutter_test.dart';
import 'package:your_app/widgets/counter_widget.dart';

void main() {
testWidgets('Counter increments when button pressed', (WidgetTester tester) async {
// Build the widget
await [Link](
MaterialApp(
home: Scaffold(
body: CounterWidget(),
),
),
);

// Verify initial state


expect([Link]('Count: 0'), findsOneWidget);
expect([Link]('Count: 1'), findsNothing);

// Tap the button


await [Link]([Link](Key('increment_button')));

// Rebuild the widget with the new state


await [Link]();

// Verify the counter incremented


expect([Link]('Count: 0'), findsNothing);
expect([Link]('Count: 1'), findsOneWidget);
} );
}

Finding Widgets

dart

[Link]('Hello'); // By text
[Link](Key('my_key')); // By key (RECOMMENDED)
[Link](ElevatedButton); // By widget type
[Link]([Link]); // By icon
[Link](ElevatedButton, 'Click'); // Widget with text
[Link]( // Nested search
of: [Link](Container),
matching: [Link]('Child'),
);

Interactions

dart
await [Link]([Link](Key('button'))); // Tap
await [Link]([Link](Key('button'))); // Long press
await [Link]([Link](ListView), Offset(0, -200)); // Scroll
await [Link]([Link](Key('input')), 'text'); // Type text

// Rebuild after interaction


await [Link](); // Single frame
await [Link](); // Until animations complete
await [Link](Duration(seconds: 1)); // Specific duration

Testing with Dependencies

dart

testWidgets('Shows user data from service', (tester) async {


// Create mock
final mockUserService = MockUserService();
when([Link]('1'))
.thenAnswer((_) async => User(id: '1', name: 'John'));

// Provide dependency
await [Link](
MaterialApp(
home: Provider<UserService>(
create: (_) => mockUserService,
child: UserScreen(userId: '1'),
),
),
);

await [Link]();

expect([Link]('John'), findsOneWidget);
} );

Golden Tests (Screenshot Tests)

dart
testWidgets('Golden test for button', (tester) async {
await [Link](
MaterialApp(
home: ElevatedButton(
onPressed: () {},
child: Text('Click Me'),
),
),
);

await expectLater(
[Link](ElevatedButton),
matchesGoldenFile('goldens/[Link]'),
);
} );

// Run: flutter test --update-goldens to generate images

Integration Tests
What are Integration Tests?

End-to-end tests that run the full app on a device/emulator. They test complete user flows.

Setup

dart
// integration_test/app_test.dart
import 'package:flutter_test/flutter_test.dart';
import 'package:integration_test/integration_test.dart';
import 'package:your_app/[Link]' as app;

void main() {
[Link]();

group('App Test', () {
testWidgets('Complete login flow', (tester) async {
// Start the app
[Link]();
await [Link]();

// Verify we're on login screen


expect([Link]('Login'), findsOneWidget);

// Enter credentials
await [Link](
[Link](Key('email_field')),
'test@[Link]',
);
await [Link](
[Link](Key('password_field')),
'password123',
);

// Submit
await [Link]([Link](Key('login_button')));
await [Link]();

// Verify navigation to home


expect([Link]('Home Screen'), findsOneWidget);
} );

testWidgets('Add item to cart flow', (tester) async {


[Link]();
await [Link]();

// Navigate to products
await [Link]([Link](Icons.shopping_bag));
await [Link]();

// Add first product


await [Link]([Link](Key('add_to_cart_0')));
await [Link]();

// Go to cart
await [Link]([Link](Icons.shopping_cart));
await [Link]();

// Verify item in cart


expect([Link](Key('cart_item')), findsOneWidget);
} );
} );
}

Running Integration Tests

bash

# Run on connected device/emulator


flutter test integration_test/app_test.dart

# Run on specific device


flutter test integration_test/app_test.dart -d <device-id>

# Generate coverage
flutter test --coverage integration_test/app_test.dart

Best Practices
1. Use Keys for Widgets

dart
// ✅ Good
ElevatedButton(
key: Key('submit_button'),
child: Text('Submit'),
onPressed: () {},
)

// ❌ Bad - finding by text is fragile


ElevatedButton(
child: Text('Submit'),
onPressed: () {},
)

2. AAA Pattern (Arrange-Act-Assert)

dart

test('calculates total price', () {


// Arrange - Setup
final cart = ShoppingCart();
[Link](Item(price: 10.0));

// Act - Execute
final total = [Link]();

// Assert - Verify
expect(total, 10.0);
} );

3. Test One Thing Per Test

dart
// ✅ Good
test('should add item to list', () {
[Link](item);
expect([Link], 1);
} );

test('should remove item from list', () {


[Link](item);
[Link](item);
expect([Link], 0);
} );

// ❌ Bad - testing too much


test('should add and remove items', () {
[Link](item);
expect([Link], 1);
[Link](item);
expect([Link], 0);
} );

4. Use setUp and tearDown

dart

group('Database tests', () {
late Database db;

setUp(() async {
db = await [Link]();
} );

tearDown(() async {
await [Link]();
} );

test('inserts data', () async {


await [Link]('test');
expect(await [Link](), 1);
} );
} );
5. Test Edge Cases

dart

group('User age validation', () {


test('accepts valid age', () {
expect(validateAge(25), true);
} );

test('rejects negative age', () {


expect(validateAge(-1), false);
} );

test('rejects age over 150', () {


expect(validateAge(151), false);
} );

test('handles zero', () {
expect(validateAge(0), false);
} );

test('handles boundary values', () {


expect(validateAge(1), true);
expect(validateAge(150), true);
} );
} );

6. Mock External Dependencies

dart

// Always mock: APIs, databases, file systems, time, random values


test('fetches data from API', () async {
final mockApi = MockApiClient();
when([Link]()).thenAnswer((_) async => mockData);

final result = await [Link]();

expect(result, mockData);
} );
7. Test Coverage

bash

# Generate coverage report


flutter test --coverage

# View in browser (requires lcov)


genhtml coverage/[Link] -o coverage/html
open coverage/html/[Link]

Aim for:

Unit tests: 80-90% coverage


Widget tests: 60-70% coverage
Integration tests: Critical user flows

Common Interview Questions


Q1: What's the difference between unit, widget, and integration tests?
Answer:

Unit tests test individual functions/classes in isolation (business logic)


Widget tests test UI components in isolation (single widgets/screens)
Integration tests test the full app end-to-end (complete user flows)

Q2: How do you mock dependencies in Flutter?

Answer: Use the mockito package with @GenerateMocks annotation to generate mock classes, then use when() to stub
methods and verify() to check calls.

Q3: What is pumpAndSettle()?

Answer: It repeatedly rebuilds the widget tree until all animations complete and the UI stabilizes. Use it after
interactions that trigger animations or async operations.

Q4: How do you test async code?

Answer: Mark test functions as async and use await:

dart
test('fetches data', () async {
final data = await fetchData();
expect(data, isNotNull);
} );

Q5: What are golden tests?


Answer: Snapshot tests that compare rendered widget screenshots against baseline images to catch visual regressions.

Q6: How do you handle setState in tests?

Answer: Call await [Link]() after interactions that trigger setState() to rebuild the widget tree.

Q7: What's the purpose of Keys?


Answer: Keys help identify and find specific widgets in tests. They provide stable references that don't depend on text or
position.

Q8: How do you test navigation?

Answer: Use [Link]() and verify the new route appears:

dart

await [Link]([Link](Key('login_button')));
await [Link]();
expect([Link](HomeScreen), findsOneWidget);

Q9: What's code coverage and what's a good target?

Answer: Percentage of code executed by tests. Good targets: 80%+ for business logic, 60-70% for UI, 100% for critical
paths.

Q10: How do you test widgets that use InheritedWidget/Provider?

Answer: Wrap the widget under test with the provider:

dart
await [Link](
Provider<MyService>(
create: (_) => mockService,
child: MyWidget(),
),
);

Quick Reference
Test Commands

bash

flutter test # Run all tests


flutter test test/models/ # Run specific folder
flutter test test/user_test.dart # Run specific file
flutter test --coverage # With coverage
flutter test integration_test/ # Run integration tests

Common Test Structure

dart
void main() {
group('Feature Name', () {
late MyClass instance;

setUp(() {
instance = MyClass();
} );

tearDown(() {
[Link]();
} );

test('should do something', () {
// Arrange
final input = 'test';

// Act
final result = [Link](input);

// Assert
expect(result, expectedValue);
} );
} );
}

Testing Checklist

✅ Test business logic (unit tests)


✅ Test UI components (widget tests)
✅ Test critical user flows (integration tests)
✅ Test edge cases and error handling
✅ Mock external dependencies
✅ Use descriptive test names
✅ Keep tests independent
✅ Aim for good coverage
✅ Run tests before commits

Additional Resources
Official Flutter Testing Docs: [Link]
Mockito Package: [Link]
Integration Testing: [Link]
Good luck with your interviews! 🚀

You might also like