7 questions foundWhat is a unit test in Flutter, and how does the flutter_test package's own test function let you write and organize a genuinely simple basic test?
Beginner A unit test verifies that one single small isolated piece of logic, such as a single function or a single class's own particular method, behaves genuinely exactly as expected when given a specific set of inputs, and the test function, provided directly by the flutter_test package, lets you properly define an individual named test containing your own actual test logic, typically calling the specific function or method genuinely under test and then properly asserting the resulting actual output correctly matches your own genuinely expected value.
test('add returns the correct sum', () {
expect(add(2, 3), equals(5));
});
Real-world example A developer writes a genuinely simple unit test verifying that a calculateDiscount function correctly returns the exact expected discounted price for a given specific input price and discount percentage.
Common follow-ups: What genuinely does the expect function actually specifically do when a given test's own assertion genuinely fails?;How do you actually properly organize several genuinely related tests together using the group function?
Dart Language Basics & Syntax;Widget Testing in Flutter
What are matchers in Flutter testing, such as equals, isTrue, and throwsA, and how do they let you express several genuinely different kinds of specific assertions within a given test?
Beginner A matcher is a genuinely specific object that describes exactly what condition a given actual value should genuinely satisfy, and the expect function uses these particular matchers to properly verify a wide genuine variety of different conditions, including equals for checking genuine exact equality, isTrue and isFalse for checking a genuine boolean condition, contains for checking whether a specific given collection actually genuinely includes a particular expected item, and throwsA for properly verifying that a given piece of code genuinely throws a specific expected exception type.
expect(() => divide(10, 0), throwsA(isA<ArgumentError>()));
expect([1, 2, 3], contains(2));
Real-world example A test verifying a division function correctly throws an ArgumentError specifically when dividing by zero uses the throwsA matcher combined with isA to precisely verify both that a genuine exception was actually thrown and that it was genuinely the exact correct expected specific type.
Common follow-ups: What genuinely other useful built in matchers does the flutter_test package already provide beyond these particular commonly used ones?;Can you actually genuinely write your own fully custom matcher for a genuinely specific particular need not already covered by the existing built in ones?
Dart Language Basics & Syntax;Error Handling & Crash Reporting (Sentry & Crashlytics)
How do setUp and tearDown let you properly share common test setup and cleanup logic consistently across several genuinely separate related tests within the exact same group?
Intermediate setUp is genuinely called automatically before every single individual test genuinely runs within its own enclosing group, letting you properly perform common shared setup work, such as creating a fresh new instance of the specific class actually genuinely being tested, ensuring every single test genuinely starts from exactly the same clean, consistent known starting state, while tearDown is genuinely called automatically after every single test genuinely completes, letting you properly clean up any resources that particular test may have actually used, such as properly closing a test database connection.
late Calculator calculator;
setUp(() {
calculator = Calculator();
});
test('adds two numbers', () {
expect(calculator.add(2, 3), 5);
});
Real-world example A test suite for a Calculator class uses setUp to properly create a genuinely fresh new Calculator instance before each individual separate test, correctly ensuring no leftover state from one particular test could ever accidentally affect a genuinely separate subsequent test.
Common follow-ups: What genuinely happens if setUp itself genuinely throws an exception partway through?;What is the specific practical difference between setUp and the considerably less commonly used setUpAll?
Dependency Injection in Flutter (GetIt & Service Locator);Widget Testing in Flutter
How do you properly use the mockito package to create a genuine mock object specifically for testing a class that genuinely depends on an external dependency, such as a network client or a database repository?
Intermediate The mockito package lets you generate a genuine mock implementation of a given interface or class, letting you precisely configure exactly what that particular mock should genuinely return when a given specific method is actually called, and then subsequently verify exactly how many times, and with exactly what specific arguments, that particular mocked method was genuinely actually called, letting you thoroughly test a class's own genuine business logic in complete isolation without needing an actual real implementation of whatever external dependency it genuinely relies on.
class MockApiClient extends Mock implements ApiClient {}
test('fetchUser returns parsed user', () async {
final mockClient = MockApiClient();
when(mockClient.get('/user')).thenAnswer((_) async => {'name': 'Alex'});
final service = UserService(mockClient);
expect((await service.fetchUser()).name, 'Alex');
});
Real-world example A test for a UserService class uses a mockito generated MockApiClient configured to return predetermined test data, thoroughly verifying the UserService's own actual parsing logic without ever needing to genuinely make a real network request.
Common follow-ups: What genuinely does the verify function specifically let you actually properly assert about a given mocked method call?;What is the specific practical difference between mockito's own traditional mocks and the considerably newer code generation based Mockito annotations?
Dependency Injection in Flutter (GetIt & Service Locator);Networking with HTTP & Dio
How do you properly measure and interpret test coverage for your Flutter app using the flutter test --coverage command, and what genuinely does the resulting coverage report actually specifically tell you?
Intermediate Running flutter test with the coverage flag generates a genuinely detailed report showing exactly which specific lines of your own actual source code were actually genuinely executed at least once while running your entire test suite, and while a genuinely high overall coverage percentage is generally a positive sign, it genuinely does not by itself guarantee your tests are actually genuinely thorough or meaningfully effective, since a specific line of code can genuinely be executed without your test actually properly asserting anything meaningful at all about the resulting genuine correctness of that particular code's own actual behavior.
flutter test --coverage
genhtml coverage/lcov.info -o coverage/html
Real-world example A team generates a detailed HTML coverage report from their test suite, discovering a genuinely critical piece of error handling logic within their checkout flow had zero actual test coverage at all, and properly writes a dedicated new test specifically to cover that particular important gap.
Common follow-ups: What genuinely reasonable target coverage percentage should a typical team reasonably aim for?;How do you actually properly visualize a generated coverage report to precisely identify exactly which specific files genuinely need considerably more test coverage?
CI/CD Pipelines for Flutter Apps;Flutter DevTools & Debugging
How do you properly write parameterized tests that run the exact same test logic against several genuinely different sets of input data, avoiding needing to duplicate that exact same test method several genuinely separate times?
Advanced Parameterized testing in Dart typically involves creating a list of genuinely different input and expected output combinations, then properly looping through that particular list and calling the test function once for each individual data set, effectively running the exact same underlying test logic against every single one of those separate genuinely different scenarios, which considerably reduces genuinely duplicated test code and makes it noticeably easier to add coverage for a genuinely new additional edge case simply by adding just one single new entry to that particular existing shared data list.
final testCases = [(1, 1, 2), (2, 3, 5), (-1, 1, 0)];
for (final (a, b, expected) in testCases) {
test('add($a, $b) equals $expected', () {
expect(add(a, b), expected);
});
}
Real-world example A team tests their currency conversion function against a dozen genuinely different specific currency pairs using a parameterized approach, avoiding writing a dozen nearly identical separate test methods that would have otherwise only genuinely differed in their specific particular input values.
Common follow-ups: How readable are the resulting individual test names when using this particular parameterized testing approach?;What genuinely other packages exist specifically to help make writing parameterized tests in Dart considerably more genuinely convenient?
Dart Language Basics & Syntax;Dart Collections & Generics
How should a large team properly establish testing conventions and standards, including deciding on a genuinely reasonable required minimum coverage threshold and properly enforcing it through their CI pipeline?
Advanced A large team benefits considerably from establishing genuinely clear, documented testing conventions, including a genuinely consistent naming pattern for individual test files and test descriptions, clear guidelines on precisely which specific kinds of logic genuinely require dedicated unit test coverage, and a properly enforced minimum coverage threshold configured directly within their CI pipeline that automatically fails a given build if a newly submitted pull request would genuinely cause overall test coverage to actually drop below that established threshold, ensuring the entire team consistently maintains a genuinely strong baseline level of test coverage as their codebase continues to steadily grow larger over time.
# CI pipeline step failing the build if coverage drops below 80%
- run: flutter test --coverage && check_coverage_threshold.sh 80
Real-world example A large engineering team configures their CI pipeline to automatically fail any pull request that would genuinely cause their overall test coverage to drop below an established eighty percent threshold, ensuring every single developer consistently maintains a genuinely strong baseline level of test coverage across their entire large shared codebase.
Common follow-ups: What genuinely reasonable minimum coverage threshold is generally appropriate for a typical production Flutter app?;How do you actually properly handle a genuinely legitimate specific exception where a particular piece of code truly cannot reasonably be properly unit tested?
CI/CD Pipelines for Flutter Apps;Flutter Architecture Patterns (MVVM & Clean Architecture)