0
0
Fluttermobile~20 mins

Test coverage in Flutter - Mini App: Build & Ship

Choose your learning style9 modes available
Build: Simple Counter Test
A screen with a counter and a button to increase the count. We want to write tests to cover the button tap and counter display.
Target UI
Counter: 0

[ Increment ]
Display a number starting at 0
A button labeled 'Increment' that increases the number by 1 when tapped
Write a widget test to verify the initial counter value is 0
Write a widget test to verify tapping the button increments the counter
Starter Code
Flutter
import 'package:flutter/material.dart';

class CounterScreen extends StatefulWidget {
  @override
  State<CounterScreen> createState() => _CounterScreenState();
}

class _CounterScreenState extends State<CounterScreen> {
  int _counter = 0;

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

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('Counter Test')),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Text('Counter: $_counter', key: const Key('counterText')),
            const SizedBox(height: 20),
            ElevatedButton(
              key: const Key('incrementButton'),
              onPressed: _increment,
              child: const Text('Increment'),
            ),
          ],
        ),
      ),
    );
  }
}

// TODO: Write widget tests for initial counter and increment button
Task 1
Task 2
Task 3
Solution
Flutter
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';

class CounterScreen extends StatefulWidget {
  @override
  State<CounterScreen> createState() => _CounterScreenState();
}

class _CounterScreenState extends State<CounterScreen> {
  int _counter = 0;

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

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('Counter Test')),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Text('Counter: $_counter', key: const Key('counterText')),
            const SizedBox(height: 20),
            ElevatedButton(
              key: const Key('incrementButton'),
              onPressed: _increment,
              child: const Text('Increment'),
            ),
          ],
        ),
      ),
    );
  }
}

void main() {
  testWidgets('Initial counter value is 0', (WidgetTester tester) async {
    await tester.pumpWidget(MaterialApp(home: CounterScreen()));

    expect(find.byKey(const Key('counterText')), findsOneWidget);
    expect(find.text('Counter: 0'), findsOneWidget);
  });

  testWidgets('Tapping increment button increases counter', (WidgetTester tester) async {
    await tester.pumpWidget(MaterialApp(home: CounterScreen()));

    final Finder button = find.byKey(const Key('incrementButton'));
    await tester.tap(button);
    await tester.pump();

    expect(find.text('Counter: 1'), findsOneWidget);
  });
}

This code defines a simple counter screen with a button to increase the count. The key parts are:

  • The counter text has a key 'counterText' so tests can find it easily.
  • The increment button has a key 'incrementButton' for testing taps.
  • Two widget tests are written:
    • One checks the initial counter text is 'Counter: 0'.
    • The other taps the increment button and verifies the counter updates to 'Counter: 1'.
  • This shows how to write basic test coverage for UI behavior in Flutter.
Final Result
Completed Screen
Counter: 0

[ Increment ]
User sees the counter starting at 0
User taps the 'Increment' button
Counter text updates to 1
Stretch Goal
Add a decrement button that decreases the counter but never below 0, and write tests for it.
💡 Hint
Add a new ElevatedButton with key 'decrementButton' and check counter does not go below zero in tests.