iOS application built using SwiftUI, Swift Concurrency, and the Observation framework. The application fetches random user profiles from the [Random User Generator API] (https://randomuser.me/), provides offline persistence, real-time debounced filtering, pagination, and persistent deletion (blacklist) functionality.
The project is covered by Unit Tests following the Arrange-Act-Assert (AAA) pattern and modern async/await test practices.
- MVVM Architecture: Built using the modern
@Observablemacro (iOS 17+) for data binding and state management. - Network Layer & Protocol-Oriented Design: Decoupled network client utilizing
NetworkServiceProtocolallowing mocking for automated test suites. - Smart Data Deduplication: Automatically tracks unique identifiers (using email as a distinct ID) to filter out duplicate profiles returned by the server before updating the UI state.
- Infinite Scroll / Pagination: Features a pagination system ("Load more") to fetch additional items sequentially without resetting the current stack.
- Persistent Blacklist (Deletion): Deleted profile IDs are permanently blacklisted via localized
UserDefaultscache, ensuring they never reappear even if returned in future server payloads. - Debounced Real-Time Search: Native search bar implementation (
.searchable) tied to a concurrency-based debounce timer (500ms). Prevents redundant server/CPU overhead by executing filters only when typing pauses. - Cross-Session Offline Persistence: Automatically caches loaded users locally. On app launch, cached state is loaded immediately for an instantaneous, offline-ready UX.
This codebase is built to simulate a real-life project while maintaining an optimal balance between modularization and clean readability, avoiding unnecessary over-engineering.
- State Leakage Protection: Unit tests comprehensively clear local persistent containers (
UserDefaults) prior to every test cycle execution to keep test environments isolated and reproducible. - Concurrency First: Employs modern
async/await, structured concurrency (Task), andMainActorcontext switching instead of deprecated GCD closures or heavy Combine streams. - Separation of Concerns: Views contain zero business logic. Data fetching, pagination indexes, search debouncers, and persistence pipelines reside completely inside the isolated
UsersViewModel.
Special attention was paid to the automated test suite. Tests are designed using the Arrange, Act, Assert pattern.
The test target covers the core business mechanics:
testFetchInitialUsers_Success_PopulatesUsersArray: Verifies success workflows, lifecycle states (isLoading), and state mutations.testFetchInitialUsers_WithDuplicates_RemovesDuplicates: Verifies the data deduplication algorithm under mock overlapping payloads.testDeleteUser_AddsToBlacklistAndFiltersFromFutureFetches: Validates the persistent blacklist lifecycle across multiple simulated page expansions.testSearchText_WithDebounce_FiltersUsers: Asserts time-dependent timeline delays, verifying the 500ms debounce window operates correctly before applying text filter logic.testFetchInitialUsers_NetworkError_SetsErrorMessage: Assures failure paths, checking that errors are propagated cleanly to the UI state.testFetchNextPageIfNeeded_Success_AppendsUsers: Confirms correct array appending behavior during pagination workflows.
- Language: Swift 5.10+
- Framework: SwiftUI (with native
.searchableand.swipeActions) - State Management: Observation Framework (
@Observable) - Asynchronous Engine: Swift Concurrency (
async/await,Task,MainActor) - Local Persistence: Codable / JSON Pipeline +
UserDefaults - Test Engine: XCTest Suite
- Clone or download this repository.
- Open
RandomUserTestTask.xcodeprojusing Xcode 15 or newer. - Select an iOS 17.0+ Simulator or real device as the run target.
- Press
⚙️ CMD + Rto compile and run the application. - Press
🧪 CMD + Uto execute the comprehensive Unit Test suite.