currency_converter

๐Ÿงช 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:

Testing Libraries


๐Ÿ“ 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:

  1. Data Source Tests: Test API calls and data transformation
  2. Repository Tests: Test error handling and data flow
  3. Use Case Tests: Test business logic and validation
  4. Cubit Tests: Test state management and UI logic

๐Ÿš€ Running Tests

Run All Tests

flutter test

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

flutter test --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:

Coverage Goals


๐ŸŽจ Feature Tests

๐Ÿ’ฑ Currency Converter Feature

Data Source Tests (data_source_test.dart)

Tests the CurrencyConverterDataSource implementation.

Test Cases:

  1. โœ… Success Case
    • Test: should return rate when API succeeds
    • Scenario: API returns valid exchange rate
    • Expected: Returns the exchange rate (e.g., 30.5)
  2. โŒ Error Case - Null Rate
    • Test: should throw exception when rate is null
    • Scenario: API returns null rate value
    • Expected: Throws ServerException

Coverage:


Repository Tests (repository_test.dart)

Tests the CurrencyConverterRepositoryImpl error handling and data flow.

Test Cases:

  1. โœ… Success Case
    • Test: should return Right when data source succeeds
    • Scenario: Data source returns valid rate
    • Expected: Returns Right(30.5)
  2. โŒ Error Case - Server Exception
    • Test: should return Left when ServerException occurs
    • Scenario: Data source throws ServerException
    • Expected: Returns Left(ServerFailure)
  3. โŒ Error Case - Network Error
    • Test: should return Left when no internet connection
    • Scenario: DioException with connection error
    • Expected: Returns Left(ServerFailure)

Coverage:


Use Case Tests (use_case_test.dart)

Tests the ConvertCurrencyUseCase business logic and validation.

Test Cases:

  1. โœ… Valid Parameters
    • Test: should return Right when parameters are valid
    • Scenario: Valid from and to currency codes
    • Expected: Returns Right(30.5) from repository
  2. โŒ Empty From Parameter
    • Test: should return error when from is empty
    • Scenario: Empty from currency code
    • Expected: Returns Left(ServerFailure('Invalid parameters'))
  3. โŒ Repository Error
    • Test: should pass through error from repository
    • Scenario: Repository returns error
    • Expected: Error is propagated without modification

Coverage:


Cubit Tests (cubit_test.dart)

Tests the CurrencyConverterCubit state management and user interactions.

Test Cases:

  1. Initial State
    • Test: should start with Initial state
    • Expected: Cubit starts with CurrencyConverterInitial
  2. Convert Currency - Success
    • Test: should emit Loading then Loaded on success
    • Scenario: Successful currency conversion
    • Expected States:
      • CurrencyConverterLoading
      • CurrencyConverterLoaded with rate 30.5
  3. Convert Currency - Error
    • Test: should emit Loading then Error on failure
    • Scenario: Use case returns error
    • Expected States:
      • CurrencyConverterLoading
      • CurrencyConverterError with error message
  4. Amount Calculation
    • Test: should calculate converted amount correctly
    • Scenario: Amount = 100, Rate = 30.5
    • Expected: convertedAmount = 3050.0
  5. State Updates
    • Test: should update currencies
    • Scenario: Setting from and to currencies
    • Expected: Emits CurrencyConverterUpdated states
  6. Amount Update
    • Test: should update amount
    • Scenario: Setting amount value
    • Expected: Amount is updated correctly
  7. Currency Swap
    • Test: should swap currencies
    • Scenario: Swapping from and to currencies
    • Expected: Currencies are swapped correctly
  8. Converted Amount Getter
    • Test: should calculate amount times rate
    • Scenario: Amount and rate are set
    • Expected: Returns correct calculation
  9. Null Rate Handling
    • Test: should return 0 when rate is null
    • Scenario: Rate is null
    • Expected: Returns 0.0

Coverage:


๐Ÿ“‹ Currency List Feature

Data Source Tests (data_source_test.dart)

Tests the CurrencyListDataSource with caching logic.

Test Cases:

  1. โœ… 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
  2. โœ… 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
  3. โœ… Clear Cache
    • Test: should clear local cache
    • Scenario: Clearing cached data
    • Expected: Database cache is cleared

Coverage:


Repository Tests (repository_test.dart)

Tests the CurrencyListRepositoryImpl error handling.

Test Cases:

  1. โœ… Get Currencies - Success
    • Test: should return Right when data source succeeds
    • Expected: Returns Right(List<CurrencyListEntity>)
  2. โŒ Get Currencies - Server Exception
    • Test: should return Left when ServerException occurs
    • Expected: Returns Left(ServerFailure)
  3. โŒ Get Currencies - Network Error
    • Test: should return Left when no internet connection
    • Expected: Returns Left(ServerFailure)
  4. โœ… 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>)
  5. โŒ Refresh Currencies - Failure
    • Test: should return Left when refresh fails
    • Expected: Returns Left(ServerFailure)

Coverage:


Use Case Tests (use_case_test.dart)

Tests the GetCurrenciesUseCase business logic.

Test Cases:

  1. โœ… Success Case
    • Test: should return currencies when repository succeeds
    • Expected: Returns Right(List<CurrencyListEntity>)
  2. โŒ Error Propagation
    • Test: should pass through error from repository
    • Expected: Error is propagated without modification

Coverage:


Cubit Tests (cubit_test.dart)

Tests the CurrencyListCubit state management and search functionality.

Test Cases:

  1. Initial State
    • Test: should start with Initial state
    • Expected: Starts with CurrencyListInitial
  2. Get Currencies - Success
    • Test: should emit Loading then Loaded on success
    • Expected States:
      • CurrencyListLoading
      • CurrencyListLoaded with currencies
  3. Get Currencies - Error
    • Test: should emit Loading then Error on failure
    • Expected States:
      • CurrencyListLoading
      • CurrencyListError with message
  4. Search Currencies
    • Test: should filter currencies by search query
    • Scenario: Search for โ€œUSDโ€
    • Expected:
      • Filters currencies
      • Updates filteredCurrencies
      • Returns matching currencies
  5. Empty Search Query
    • Test: should return all currencies when query is empty
    • Scenario: Empty search string
    • Expected: Shows all currencies
  6. Refresh Currencies - Success
    • Test: should emit Loading then Loaded on refresh success
    • Expected States:
      • CurrencyListLoading
      • CurrencyListLoaded
  7. Refresh Currencies - Error
    • Test: should emit Loading then Error on refresh failure
    • Expected States:
      • CurrencyListLoading
      • CurrencyListError

Coverage:


๐Ÿ“ˆ Historical Rates Feature

Data Source Tests (data_source_test.dart)

Tests the HistoricalRatesDataSource API integration.

Test Cases:

  1. โœ… Success Case
    • Test: should return rates when API succeeds
    • Scenario: API returns historical rates data
    • Expected: Returns list of HistoricalRateModel
  2. โŒ Empty Results
    • Test: should throw exception when results are empty
    • Scenario: API returns empty results object
    • Expected: Throws ServerException
  3. โŒ Empty Rates List
    • Test: should throw exception when rates list is empty
    • Scenario: Results object is empty
    • Expected: Throws ServerException

Coverage:


Repository Tests (repository_test.dart)

Tests the HistoricalRatesRepositoryImpl error handling.

Test Cases:

  1. โœ… Success Case
    • Test: should return Right when data source succeeds
    • Expected: Returns Right(List<HistoricalRateEntity>)
  2. โŒ Server Exception
    • Test: should return Left when ServerException occurs
    • Expected: Returns Left(ServerFailure)
  3. โŒ Network Error
    • Test: should return Left when no internet connection
    • Expected: Returns Left(ServerFailure)

Coverage:


Use Case Tests (use_case_test.dart)

Tests the GetHistoricalRatesUseCase validation and business logic.

Test Cases:

  1. โœ… Success Case
    • Test: should return rates when repository succeeds
    • Expected: Returns Right(List<HistoricalRateEntity>)
  2. โŒ Null Parameters
    • Test: should return error when params is null
    • Scenario: No parameters provided
    • Expected: Returns Left(ServerFailure('Invalid parameters'))
  3. โŒ Repository Error
    • Test: should pass through error from repository
    • Expected: Error is propagated

Coverage:


Cubit Tests (cubit_test.dart)

Tests the HistoricalRatesCubit state management.

Test Cases:

  1. Initial State
    • Test: should start with Initial state
    • Expected: Starts with HistoricalRatesInitial
  2. Set Currencies
    • Test: should set currencies and emit Idle state
    • Scenario: Setting from and to currencies
    • Expected:
      • Emits HistoricalRatesIdle
      • Currencies are set correctly
  3. 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
  4. Get Historical Rates - Success
    • Test: should emit Loading then Loaded on success
    • Expected States:
      • HistoricalRatesLoading
      • HistoricalRatesLoaded with rates
  5. Get Historical Rates - Error
    • Test: should handle error from use case
    • Scenario: Use case returns error
    • Expected: State is not HistoricalRatesLoaded
  6. Null Currencies
    • Test: should not emit states when currencies are null
    • Scenario: Currencies not set
    • Expected: Remains in HistoricalRatesInitial

Coverage:


๐ŸŽฏ Testing Strategy

Test Pyramid

        /\
       /  \      E2E Tests (Future)
      /____\
     /      \    Integration Tests (Future)
    /________\
   /          \   Widget Tests (Future)
  /____________\
 /              \  Unit Tests (Current)
/________________\

Current Focus: Unit Tests

  1. Data Source Layer: Test API calls, data transformation, error handling
  2. Repository Layer: Test error mapping, data flow, exception handling
  3. Use Case Layer: Test business logic, validation, error propagation
  4. Cubit Layer: Test state management, user interactions, state transitions

Testing Principles

  1. Isolation: Each test is independent and can run in any order
  2. Mocking: External dependencies are mocked using mocktail
  3. Arrange-Act-Assert: Clear test structure for readability
  4. Edge Cases: All error scenarios and boundary conditions are tested
  5. 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:


โœ… Test Checklist

Data Source Tests

Repository Tests

Use Case Tests

Cubit Tests


๐Ÿ”ฎ Future Test Enhancements

Widget Tests

Integration Tests

E2E Tests


๐Ÿ“š Additional Resources


Last Updated: Based on current test suite structure

Test Coverage: Comprehensive unit tests for all features and layers