๐งช Testing Documentation
Comprehensive testing documentation for the Currency Converter application.
๐ Table of Contents
๐ฏ Overview
This application follows a comprehensive testing strategy covering all layers of Clean Architecture:
- Data Layer: Data sources and API interactions
- Domain Layer: Use cases and business logic
- Presentation Layer: BLoC/Cubit state management
Testing Libraries
- flutter_test: Core Flutter testing framework
- bloc_test: Testing utilities for BLoC/Cubit
- mocktail: Mocking framework for creating test doubles
- dartz: Functional programming utilities (Either for error handling)
๐ Test Structure
The test directory mirrors the application structure:
test/
โโโ features/
โโโ currency_converter/
โ โโโ data_source_test.dart
โ โโโ repository_test.dart
โ โโโ use_case_test.dart
โ โโโ cubit_test.dart
โโโ currency_list/
โ โโโ data_source_test.dart
โ โโโ repository_test.dart
โ โโโ use_case_test.dart
โ โโโ cubit_test.dart
โโโ historical_rates/
โโโ data_source_test.dart
โโโ repository_test.dart
โโโ use_case_test.dart
โโโ cubit_test.dart
Each feature follows the same testing pattern:
- Data Source Tests: Test API calls and data transformation
- Repository Tests: Test error handling and data flow
- Use Case Tests: Test business logic and validation
- Cubit Tests: Test state management and UI logic
๐ Running Tests
Run All Tests
Run Tests for a Specific Feature
# Currency Converter
flutter test test/features/currency_converter/
# Currency List
flutter test test/features/currency_list/
# Historical Rates
flutter test test/features/historical_rates/
Run a Specific Test File
flutter test test/features/currency_converter/cubit_test.dart
Run Tests with Coverage
View Coverage Report
# Generate HTML report (requires lcov)
genhtml coverage/lcov.info -o coverage/html
open coverage/html/index.html
๐ Test Coverage
The test suite aims for comprehensive coverage across all layers:
- Data Sources: API calls, error handling, data transformation
- Repositories: Error mapping, data flow, exception handling
- Use Cases: Business logic, parameter validation, error propagation
- Cubits: State transitions, user interactions, error states
Coverage Goals
- Unit Tests: 80%+ coverage for business logic
- BLoC Tests: 100% state coverage for all Cubits
- Edge Cases: All error scenarios and boundary conditions
๐จ Feature Tests
๐ฑ Currency Converter Feature
Data Source Tests (data_source_test.dart)
Tests the CurrencyConverterDataSource implementation.
Test Cases:
- โ
Success Case
- Test:
should return rate when API succeeds
- Scenario: API returns valid exchange rate
- Expected: Returns the exchange rate (e.g., 30.5)
- โ Error Case - Null Rate
- Test:
should throw exception when rate is null
- Scenario: API returns null rate value
- Expected: Throws
ServerException
Coverage:
- โ
Successful API response handling
- โ
Null rate error handling
- โ
API service integration
Repository Tests (repository_test.dart)
Tests the CurrencyConverterRepositoryImpl error handling and data flow.
Test Cases:
- โ
Success Case
- Test:
should return Right when data source succeeds
- Scenario: Data source returns valid rate
- Expected: Returns
Right(30.5)
- โ Error Case - Server Exception
- Test:
should return Left when ServerException occurs
- Scenario: Data source throws
ServerException
- Expected: Returns
Left(ServerFailure)
- โ Error Case - Network Error
- Test:
should return Left when no internet connection
- Scenario:
DioException with connection error
- Expected: Returns
Left(ServerFailure)
Coverage:
- โ
Success path with Right value
- โ
ServerException mapping to Failure
- โ
Network error handling (DioException)
- โ
Error propagation from data source
Use Case Tests (use_case_test.dart)
Tests the ConvertCurrencyUseCase business logic and validation.
Test Cases:
- โ
Valid Parameters
- Test:
should return Right when parameters are valid
- Scenario: Valid
from and to currency codes
- Expected: Returns
Right(30.5) from repository
- โ Empty From Parameter
- Test:
should return error when from is empty
- Scenario: Empty
from currency code
- Expected: Returns
Left(ServerFailure('Invalid parameters'))
- โ Repository Error
- Test:
should pass through error from repository
- Scenario: Repository returns error
- Expected: Error is propagated without modification
Coverage:
- โ
Parameter validation (empty strings)
- โ
Success path delegation to repository
- โ
Error propagation from repository
- โ
Business rule enforcement
Cubit Tests (cubit_test.dart)
Tests the CurrencyConverterCubit state management and user interactions.
Test Cases:
- Initial State
- Test:
should start with Initial state
- Expected: Cubit starts with
CurrencyConverterInitial
- Convert Currency - Success
- Test:
should emit Loading then Loaded on success
- Scenario: Successful currency conversion
- Expected States:
CurrencyConverterLoading
CurrencyConverterLoaded with rate 30.5
- Convert Currency - Error
- Test:
should emit Loading then Error on failure
- Scenario: Use case returns error
- Expected States:
CurrencyConverterLoading
CurrencyConverterError with error message
- Amount Calculation
- Test:
should calculate converted amount correctly
- Scenario: Amount = 100, Rate = 30.5
- Expected:
convertedAmount = 3050.0
- State Updates
- Test:
should update currencies
- Scenario: Setting from and to currencies
- Expected: Emits
CurrencyConverterUpdated states
- Amount Update
- Test:
should update amount
- Scenario: Setting amount value
- Expected: Amount is updated correctly
- Currency Swap
- Test:
should swap currencies
- Scenario: Swapping from and to currencies
- Expected: Currencies are swapped correctly
- Converted Amount Getter
- Test:
should calculate amount times rate
- Scenario: Amount and rate are set
- Expected: Returns correct calculation
- Null Rate Handling
- Test:
should return 0 when rate is null
- Scenario: Rate is null
- Expected: Returns 0.0
Coverage:
- โ
Initial state
- โ
Loading state transitions
- โ
Success state with data
- โ
Error state handling
- โ
Currency selection and updates
- โ
Amount input and calculation
- โ
Currency swapping
- โ
Converted amount calculation
- โ
Null safety handling
๐ Currency List Feature
Data Source Tests (data_source_test.dart)
Tests the CurrencyListDataSource with caching logic.
Test Cases:
- โ
Fetch from API (No Cache)
- Test:
should return currencies from API when no cache
- Scenario: No cached data available
- Expected:
- Fetches from API
- Saves to database
- Returns currency list
- โ
Fetch from Cache
- Test:
should return currencies from cache when available
- Scenario: Cached data exists in database
- Expected:
- Returns cached currencies
- No API call made
- โ
Clear Cache
- Test:
should clear local cache
- Scenario: Clearing cached data
- Expected: Database cache is cleared
Coverage:
- โ
API fetching when no cache
- โ
Cache retrieval
- โ
Cache persistence
- โ
Cache clearing
- โ
Database integration
Repository Tests (repository_test.dart)
Tests the CurrencyListRepositoryImpl error handling.
Test Cases:
- โ
Get Currencies - Success
- Test:
should return Right when data source succeeds
- Expected: Returns
Right(List<CurrencyListEntity>)
- โ Get Currencies - Server Exception
- Test:
should return Left when ServerException occurs
- Expected: Returns
Left(ServerFailure)
- โ Get Currencies - Network Error
- Test:
should return Left when no internet connection
- Expected: Returns
Left(ServerFailure)
- โ
Refresh Currencies - Success
- Test:
should return Right when refresh succeeds
- Scenario: Clearing cache and fetching new data
- Expected:
- Cache cleared
- New data fetched
- Returns
Right(List<CurrencyListEntity>)
- โ Refresh Currencies - Failure
- Test:
should return Left when refresh fails
- Expected: Returns
Left(ServerFailure)
Coverage:
- โ
Success path for get currencies
- โ
Success path for refresh
- โ
ServerException handling
- โ
Network error handling
- โ
Cache clearing on refresh
Use Case Tests (use_case_test.dart)
Tests the GetCurrenciesUseCase business logic.
Test Cases:
- โ
Success Case
- Test:
should return currencies when repository succeeds
- Expected: Returns
Right(List<CurrencyListEntity>)
- โ Error Propagation
- Test:
should pass through error from repository
- Expected: Error is propagated without modification
Coverage:
- โ
Success path delegation
- โ
Error propagation
Cubit Tests (cubit_test.dart)
Tests the CurrencyListCubit state management and search functionality.
Test Cases:
- Initial State
- Test:
should start with Initial state
- Expected: Starts with
CurrencyListInitial
- Get Currencies - Success
- Test:
should emit Loading then Loaded on success
- Expected States:
CurrencyListLoading
CurrencyListLoaded with currencies
- Get Currencies - Error
- Test:
should emit Loading then Error on failure
- Expected States:
CurrencyListLoading
CurrencyListError with message
- Search Currencies
- Test:
should filter currencies by search query
- Scenario: Search for โUSDโ
- Expected:
- Filters currencies
- Updates
filteredCurrencies
- Returns matching currencies
- Empty Search Query
- Test:
should return all currencies when query is empty
- Scenario: Empty search string
- Expected: Shows all currencies
- Refresh Currencies - Success
- Test:
should emit Loading then Loaded on refresh success
- Expected States:
CurrencyListLoading
CurrencyListLoaded
- Refresh Currencies - Error
- Test:
should emit Loading then Error on refresh failure
- Expected States:
CurrencyListLoading
CurrencyListError
Coverage:
- โ
Initial state
- โ
Loading and loaded states
- โ
Error state handling
- โ
Search functionality
- โ
Filter logic
- โ
Empty search handling
- โ
Refresh functionality
- โ
State transitions
๐ Historical Rates Feature
Data Source Tests (data_source_test.dart)
Tests the HistoricalRatesDataSource API integration.
Test Cases:
- โ
Success Case
- Test:
should return rates when API succeeds
- Scenario: API returns historical rates data
- Expected: Returns list of
HistoricalRateModel
- โ Empty Results
- Test:
should throw exception when results are empty
- Scenario: API returns empty results object
- Expected: Throws
ServerException
- โ Empty Rates List
- Test:
should throw exception when rates list is empty
- Scenario: Results object is empty
- Expected: Throws
ServerException
Coverage:
- โ
Successful API response parsing
- โ
Empty results handling
- โ
Empty rates list handling
- โ
Date parsing and rate extraction
Repository Tests (repository_test.dart)
Tests the HistoricalRatesRepositoryImpl error handling.
Test Cases:
- โ
Success Case
- Test:
should return Right when data source succeeds
- Expected: Returns
Right(List<HistoricalRateEntity>)
- โ Server Exception
- Test:
should return Left when ServerException occurs
- Expected: Returns
Left(ServerFailure)
- โ Network Error
- Test:
should return Left when no internet connection
- Expected: Returns
Left(ServerFailure)
Coverage:
- โ
Success path
- โ
ServerException mapping
- โ
Network error handling
Use Case Tests (use_case_test.dart)
Tests the GetHistoricalRatesUseCase validation and business logic.
Test Cases:
- โ
Success Case
- Test:
should return rates when repository succeeds
- Expected: Returns
Right(List<HistoricalRateEntity>)
- โ Null Parameters
- Test:
should return error when params is null
- Scenario: No parameters provided
- Expected: Returns
Left(ServerFailure('Invalid parameters'))
- โ Repository Error
- Test:
should pass through error from repository
- Expected: Error is propagated
Coverage:
- โ
Parameter validation (null check)
- โ
Success path delegation
- โ
Error propagation
Cubit Tests (cubit_test.dart)
Tests the HistoricalRatesCubit state management.
Test Cases:
- Initial State
- Test:
should start with Initial state
- Expected: Starts with
HistoricalRatesInitial
- Set Currencies
- Test:
should set currencies and emit Idle state
- Scenario: Setting from and to currencies
- Expected:
- Emits
HistoricalRatesIdle
- Currencies are set correctly
- Same Currencies (No State Change)
- Test:
should not emit new state if currencies are the same
- Scenario: Setting same currencies again
- Expected: No new state emitted
- Get Historical Rates - Success
- Test:
should emit Loading then Loaded on success
- Expected States:
HistoricalRatesLoading
HistoricalRatesLoaded with rates
- Get Historical Rates - Error
- Test:
should handle error from use case
- Scenario: Use case returns error
- Expected: State is not
HistoricalRatesLoaded
- Null Currencies
- Test:
should not emit states when currencies are null
- Scenario: Currencies not set
- Expected: Remains in
HistoricalRatesInitial
Coverage:
- โ
Initial state
- โ
Currency setting
- โ
Idle state management
- โ
Loading and loaded states
- โ
Error handling
- โ
Null currency validation
- โ
State transition prevention for same currencies
๐ฏ Testing Strategy
Test Pyramid
/\
/ \ E2E Tests (Future)
/____\
/ \ Integration Tests (Future)
/________\
/ \ Widget Tests (Future)
/____________\
/ \ Unit Tests (Current)
/________________\
Current Focus: Unit Tests
- Data Source Layer: Test API calls, data transformation, error handling
- Repository Layer: Test error mapping, data flow, exception handling
- Use Case Layer: Test business logic, validation, error propagation
- Cubit Layer: Test state management, user interactions, state transitions
Testing Principles
- Isolation: Each test is independent and can run in any order
- Mocking: External dependencies are mocked using
mocktail
- Arrange-Act-Assert: Clear test structure for readability
- Edge Cases: All error scenarios and boundary conditions are tested
- State Coverage: All possible state transitions are tested
๐ ๏ธ Test Utilities
Mocking Framework: mocktail
Used for creating mock objects:
class MockApiService extends Mock implements ApiService {}
class MockRepository extends Mock implements Repository {}
BLoC Testing: bloc_test
Used for testing BLoC/Cubit state management:
blocTest<Cubit, State>(
'description',
build: () => cubit,
act: (cubit) => cubit.action(),
expect: () => [State1(), State2()],
);
Error Handling: dartz
Used for functional error handling with Either:
Either<Failure, Success>
- Right(value): Success case
- Left(failure): Error case
๐ Test Naming Convention
Tests follow a clear naming pattern:
- Format:
should [expected behavior] when [condition]
- Examples:
should return rate when API succeeds
should throw exception when rate is null
should emit Loading then Loaded on success
โ
Test Checklist
Data Source Tests
Repository Tests
Use Case Tests
Cubit Tests
๐ฎ Future Test Enhancements
- Test individual widget rendering
- Test widget interactions
- Test widget state changes
Integration Tests
- Test complete user flows
- Test feature interactions
- Test navigation flows
E2E Tests
- Test app launch and initialization
- Test complete user journeys
- Test offline/online scenarios
๐ Additional Resources
Last Updated: Based on current test suite structure
Test Coverage: Comprehensive unit tests for all features and layers