RÉSUMÉ
[Développement Mobile] Tester vos applications mobiles en 2026 : Guide complet des tests unitaires, d’intégration et UI
Maîtrisez les tests unitaires, d’intégration et UI pour Android et iOS afin de garantir la qualité de vos applications mobiles en 2026.
Keywords: Développement mobile, Tests mobiles, Qualité logicielle
TABLE DES MATIÈRES
1 Introduction : L’Impératif du Testing Mobile en 2026
2 Les Fondamentaux du Test Unitaire
3 Les Tests d’Intégration : Vérifier les Interactions
4 Les Tests UI : L’Expérience Utilisateur à la Loupe
5 Défis et Solutions Courantes en Testing Mobile
6 Stratégies de Test Avancées et Automatisation
7 FAQ sur le Testing Mobile
8 Conclusion : Vers des Applications Mobiles Infaillibles
INTRODUCTION
L’Impératif du Testing Mobile en 2026
Dans le paysage numérique de 2026, les applications mobiles sont plus qu’une simple commodité ; elles sont devenues le pilier de notre interaction avec le monde. Des services bancaires aux réseaux sociaux, en passant par le divertissement et la productivité, nos vies sont intrinsèquement liées à la performance et à la fiabilité de ces outils. Cependant, la complexité croissante des écosystèmes mobiles, caractérisée par une multitude de dispositifs, de systèmes d’exploitation (Android et iOS) et de versions, pose un défi majeur : garantir une qualité irréprochable.
L’échec d’une application peut avoir des répercussions désastreuses. Des études récentes montrent qu’en 2026, plus de 70% des utilisateurs désinstalleraient une application après seulement une ou deux expériences négatives, qu’il s’agisse de plantages, de lenteurs ou d’une interface utilisateur défectueuse. Pour les entreprises, cela se traduit par une perte de revenus, une dégradation de la réputation de la marque et un gaspillage des efforts de développement. Le testing mobile n’est donc plus une option, mais une nécessité stratégique pour toute organisation souhaitant prospérer dans l’économie des applications.
« Une application non testée est une application en attente d’un échec. »
— Kwontenu, Expert en Qualité Logicielle
Ce guide complet vous plongera dans les arcanes des tests unitaires, d’intégration et UI, essentiels pour le développement d’applications Android et iOS en 2026. Nous démystifierons le jargon technique et vous fournirons les meilleures pratiques, les outils incontournables et des exemples concrets pour chaque type de test. Notre objectif est de vous outiller pour construire des applications robustes, performantes et offrant une expérience utilisateur exceptionnelle, en minimisant les risques de défauts et en maximisant la satisfaction de vos utilisateurs.
POINT CLÉ
En 2026, la fragmentation du marché mobile (plus de 25 000 modèles Android, multiples versions iOS) rend le testing manuel insuffisant. L’automatisation est cruciale pour une couverture exhaustive et une livraison rapide.
CONTENU PRINCIPAL
Les Fondamentaux du Test Unitaire
Les tests unitaires sont la première ligne de défense de votre code. Ils visent à tester les plus petites parties testables d’une application, appelées « unités », de manière isolée. Une unité peut être une fonction, une méthode, une classe ou un composant. L’objectif est de vérifier que chaque unité fonctionne comme prévu, indépendamment des autres parties du système. Cela permet de détecter les bugs très tôt dans le cycle de développement, là où ils sont les moins coûteux à corriger.
Les avantages des tests unitaires sont multiples :
- Détection précoce des bugs : Les problèmes sont identifiés avant qu’ils ne s’intègrent dans des systèmes plus complexes.
- Confiance dans le refactoring : Modifier le code devient moins risqué, car les tests garantissent que les fonctionnalités existantes ne sont pas cassées.
- Amélioration de la conception du code : Écrire des tests unitaires encourage un code plus modulaire, découplé et facile à maintenir.
- Documentation vivante : Les tests servent de documentation sur le comportement attendu de chaque unité.
- Feedback rapide : Les tests unitaires s’exécutent généralement en quelques millisecondes, offrant un retour immédiat au développeur.
POINT CLÉ
Une bonne suite de tests unitaires peut réduire le temps de débogage de plus de 50% et augmenter la productivité des développeurs de 15% à 30%.
Sur Android, JUnit est le framework de test unitaire standard, souvent combiné avec Mockito ou MockK pour la création de mocks et de stubs. Pour iOS, XCTest est le framework natif fourni par Apple.
Exemple de Test Unitaire Android (Kotlin)
EXPLICATION DU CODE
Cet exemple simple teste une fonction Calculator.add(). Nous utilisons JUnit et la fonction assertEquals pour vérifier que le résultat de l’addition est correct.
// src/main/java/com/kwontenu/app/Calculator.kt
package com.kwontenu.app
class Calculator {
fun add(a: Int, b: Int): Int {
return a + b
}
fun subtract(a: Int, b: Int): Int {
return a - b
}
}
// src/test/java/com/kwontenu/app/CalculatorTest.kt
package com.kwontenu.app
import org.junit.Assert.assertEquals
import org.junit.Before
import org.junit.Test
class CalculatorTest {
private lateinit var calculator: Calculator
@Before
fun setup() {
calculator = Calculator()
}
@Test
fun add_returnsCorrectSum() {
val result = calculator.add(5, 3)
assertEquals(8, result)
}
@Test
fun subtract_returnsCorrectDifference() {
val result = calculator.subtract(10, 4)
assertEquals(6, result)
}
@Test
fun add_returnsCorrectSum_negativeNumbers() {
val result = calculator.add(-5, -3)
assertEquals(-8, result)
}
}Exemple de Test Unitaire iOS (Swift)
EXPLICATION DU CODE
Cet exemple utilise XCTest pour tester une structure MathOperations. La méthode XCTAssertEqual est utilisée pour affirmer que les résultats des opérations sont conformes aux attentes.
// MathOperations.swift
import Foundation
struct MathOperations {
func add(a: Int, b: Int) -> Int {
return a + b
}
func multiply(a: Int, b: Int) -> Int {
return a * b
}
}
// MathOperationsTests.swift (dans le target de test)
import XCTest
@testable import YourAppModule // Remplacez par le nom de votre module
class MathOperationsTests: XCTestCase {
var mathOps: MathOperations!
override func setUpWithError() throws {
// Cette méthode est appelée avant l'invocation de chaque méthode de test.
mathOps = MathOperations()
}
override func tearDownWithError() throws {
// Cette méthode est appelée après l'invocation de chaque méthode de test.
mathOps = nil
}
func testAddFunction_ReturnsCorrectSum() {
let result = mathOps.add(a: 10, b: 5)
XCTAssertEqual(result, 15, "La fonction add() devrait retourner 15.")
}
func testMultiplyFunction_ReturnsCorrectProduct() {
let result = mathOps.multiply(a: 4, b: 3)
XCTAssertEqual(result, 12, "La fonction multiply() devrait retourner 12.")
}
func testAddFunction_WithNegativeNumbers() {
let result = mathOps.add(a: -7, b: 2)
XCTAssertEqual(result, -5, "La fonction add() devrait gérer les nombres négatifs.")
}
}
Pour maximiser l’efficacité de vos tests unitaires, suivez les principes F.I.R.S.T. :
- Fast (Rapides) : Les tests doivent s’exécuter rapidement pour un feedback immédiat.
- Independent (Indépendants) : Chaque test doit pouvoir s’exécuter seul, dans n’importe quel ordre.
- Repeatable (Répétables) : Les résultats doivent être les mêmes à chaque exécution, quel que soit l’environnement.
- Self-validating (Auto-validants) : Le test doit clairement indiquer s’il a réussi ou échoué.
- Timely (Opportuns) : Les tests doivent être écrits juste avant ou pendant le développement du code à tester (approche TDD).
CONTENU PRINCIPAL
Les Tests d’Intégration : Vérifier les Interactions
Après avoir vérifié les unités individuelles, il est crucial de s’assurer qu’elles fonctionnent correctement ensemble. C’est le rôle des tests d’intégration. Ces tests visent à vérifier l’interaction entre différents modules ou services d’une application, tels que la communication entre un ViewModel et un Repository, l’accès à une base de données locale, ou les appels à une API externe. L’objectif est de s’assurer que les interfaces entre les composants sont correctement implémentées et que le flux de données entre eux est cohérent.
Les tests d’intégration sont particulièrement importants pour :
- Valider les contrats d’interface : S’assurer que les composants se comprennent et échangent les données comme prévu.
- Tester les flux complexes : Vérifier des scénarios impliquant plusieurs étapes et interactions entre des couches différentes.
- Détecter les problèmes de dépendance : Identifier les erreurs liées aux configurations ou aux versions des bibliothèques.
- Assurer la persistance des données : Tester la lecture et l’écriture dans des bases de données locales (Room sur Android, Core Data/Realm sur iOS).
- Vérifier les interactions réseau : Simuler des appels API et s’assurer que l’application gère correctement les réponses et les erreurs.
« Les tests d’intégration sont le pont entre les unités isolées et le système cohérent. »
— Kwontenu, Architecte Logiciel
Les outils utilisés pour les tests d’intégration sont souvent une extension des frameworks de tests unitaires. Pour Android, AndroidX Test fournit des bibliothèques pour tester des composants Android dans un environnement Android réel ou simulé. Des frameworks de Dependency Injection comme Hilt ou Koin facilitent l’injection de mocks pour isoler les composants autant que possible. Sur iOS, XCTest est également utilisé, souvent avec des mocks pour les dépendances externes comme les services réseau.
POINT CLÉ
Les tests d’intégration sont plus lents que les tests unitaires mais plus rapides que les tests UI. Un bon équilibre est crucial pour une stratégie de test efficace.
Exemple de Test d’Intégration Android (Kotlin – ViewModel/Repository)
EXPLICATION DU CODE
Cet exemple teste l’intégration entre un UserViewModel et un UserRepository. Nous utilisons Mockito pour mocker le repository et simuler son comportement, ce qui nous permet de tester le ViewModel de manière isolée des dépendances réelles (comme une base de données ou un service réseau).
// src/main/java/com/kwontenu/app/data/UserRepository.kt
package com.kwontenu.app.data
import com.kwontenu.app.model.User
interface UserRepository {
suspend fun getUsers(): List
suspend fun getUserById(id: String): User?
}
// src/main/java/com/kwontenu/app/viewmodel/UserViewModel.kt
package com.kwontenu.app.viewmodel
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.kwontenu.app.data.UserRepository
import com.kwontenu.app.model.User
import kotlinx.coroutines.launch
class UserViewModel(private val userRepository: UserRepository) : ViewModel() {
private val _users = MutableLiveData>()
val users: LiveData> = _users
private val _isLoading = MutableLiveData()
val isLoading: LiveData = _isLoading
fun fetchUsers() {
_isLoading.value = true
viewModelScope.launch {
try {
_users.value = userRepository.getUsers()
} catch (e: Exception) {
// Gérer l'erreur
} finally {
_isLoading.value = false
}
}
}
}
// src/test/java/com/kwontenu/app/viewmodel/UserViewModelTest.kt
package com.kwontenu.app.viewmodel
import androidx.arch.core.executor.testing.InstantTaskExecutorRule
import com.kwontenu.app.data.UserRepository
import com.kwontenu.app.model.User
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.*
import org.junit.After
import org.junit.Before
import org.junit.Rule
import org.junit.Test
import org.mockito.Mockito.*
@ExperimentalCoroutinesApi
class UserViewModelTest {
@get:Rule
val instantTaskExecutorRule = InstantTaskExecutorRule() // Pour tester LiveData
private val testDispatcher = UnconfinedTestDispatcher()
private lateinit var userRepository: UserRepository
private lateinit var viewModel: UserViewModel
@Before
fun setup() {
Dispatchers.setMain(testDispatcher)
userRepository = mock(UserRepository::class.java)
viewModel = UserViewModel(userRepository)
}
@After
fun tearDown() {
Dispatchers.resetMain()
}
@Test
fun fetchUsers_loadsUsersIntoLiveData() = runTest {
val dummyUsers = listOf(User("1", "Alice"), User("2", "Bob"))
`when`(userRepository.getUsers()).thenReturn(dummyUsers)
viewModel.fetchUsers()
verify(userRepository).getUsers()
assert(viewModel.users.value == dummyUsers)
assert(viewModel.isLoading.value == false)
}
@Test
fun fetchUsers_setsLoadingState() = runTest {
`when`(userRepository.getUsers()).thenReturn(emptyList())
viewModel.fetchUsers()
assert(viewModel.isLoading.value == false) // Après la fin de l'appel
}
}

Exemple de Test d’Intégration iOS (Swift – Service/NetworkClient)
EXPLICATION DU CODE
Ici, nous testons l’intégration entre un UserService et un NetworkClient. Le MockNetworkClient simule les réponses réseau, nous permettant de vérifier que le service gère correctement les données reçues sans effectuer de véritables appels réseau.
// User.swift
import Foundation
struct User: Codable, Equatable {
let id: Int
let name: String
let email: String
}
// NetworkClient.swift
import Foundation
protocol NetworkClient {
func fetchData(from url: URL) async throws -> Data
}
class URLSessionNetworkClient: NetworkClient {
func fetchData(from url: URL) async throws -> Data {
let (data, response) = try await URLSession.shared.data(from: url)
guard let httpResponse = response as? HTTPURLResponse, httpResponse.statusCode == 200 else {
throw URLError(.badServerResponse)
}
return data
}
}
// UserService.swift
import Foundation
class UserService {
private let networkClient: NetworkClient
private let usersURL = URL(string: "https://api.example.com/users")!
init(networkClient: NetworkClient) {
self.networkClient = networkClient
}
func fetchUsers() async throws -> [User] {
let data = try await networkClient.fetchData(from: usersURL)
let decoder = JSONDecoder()
return try decoder.decode([User].self, from: data)
}
}
// MockNetworkClient.swift (dans le target de test)
import Foundation
@testable import YourAppModule // Remplacez par le nom de votre module
class MockNetworkClient: NetworkClient {
var dataToReturn: Data?
var errorToThrow: Error?
var receivedURL: URL?
func fetchData(from url: URL) async throws -> Data {
receivedURL = url
if let error = errorToThrow {
throw error
}
guard let data = dataToReturn else {
XCTFail("dataToReturn n'est pas défini pour le MockNetworkClient.")
throw URLError(.unknown)
}
return data
}
}
// UserServiceIntegrationTests.swift (dans le target de test)
import XCTest
@testable import YourAppModule // Remplacez par le nom de votre module
class UserServiceIntegrationTests: XCTestCase {
var mockNetworkClient: MockNetworkClient!
var userService: UserService!
override func setUpWithError() throws {
mockNetworkClient = MockNetworkClient()
userService = UserService(networkClient: mockNetworkClient)
}
override func tearDownWithError() throws {
mockNetworkClient = nil
userService = nil
}
func testFetchUsers_Success() async throws {
let json = """
[
{"id": 1, "name": "Alice", "email": "[email protected]"},
{"id": 2, "name": "Bob", "email": "[email protected]"}
]
"""
mockNetworkClient.dataToReturn = json.data(using: .utf8)
let users = try await userService.fetchUsers()
XCTAssertEqual(users.count, 2)
XCTAssertEqual(users[0].name, "Alice")
XCTAssertEqual(mockNetworkClient.receivedURL?.absoluteString, "https://api.example.com/users")
}
func testFetchUsers_NetworkError() async {
mockNetworkClient.errorToThrow = URLError(.notConnectedToInternet)
do {
_ = try await userService.fetchUsers()
XCTFail("La récupération des utilisateurs devrait échouer avec une erreur réseau.")
} catch {
XCTAssertTrue(error is URLError)
let urlError = error as! URLError
XCTAssertEqual(urlError.code, .notConnectedToInternet)
}
}
}
Exemple de Test d’Intégration iOS (Swift – Service/NetworkClient)
EXPLICATION DU CODE
Ici, nous testons l’intégration entre un UserService et un NetworkClient. Le MockNetworkClient simule les réponses réseau, nous permettant de vérifier que le service gère correctement les données reçues sans effectuer de véritables appels réseau.
// User.swift
import Foundation
struct User: Codable, Equatable {
let id: Int
let name: String
let email: String
}
// NetworkClient.swift
import Foundation
protocol NetworkClient {
func fetchData(from url: URL) async throws -> Data
}
class URLSessionNetworkClient: NetworkClient {
func fetchData(from url: URL) async throws -> Data {
let (data, response) = try await URLSession.shared.data(from: url)
guard let httpResponse = response as? HTTPURLResponse, httpResponse.statusCode == 200 else {
throw URLError(.badServerResponse)
}
return data
}
}
// UserService.swift
import Foundation
class UserService {
private let networkClient: NetworkClient
private let usersURL = URL(string: "https://api.example.com/users")!
init(networkClient: NetworkClient) {
self.networkClient = networkClient
}
func fetchUsers() async throws -> [User] {
let data = try await networkClient.fetchData(from: usersURL)
let decoder = JSONDecoder()
return try decoder.decode([User].self, from: data)
}
}
// MockNetworkClient.swift (dans le target de test)
import Foundation
@testable import YourAppModule // Remplacez par le nom de votre module
class MockNetworkClient: NetworkClient {
var dataToReturn: Data?
var errorToThrow: Error?
var receivedURL: URL?
func fetchData(from url: URL) async throws -> Data {
receivedURL = url
if let error = errorToThrow {
throw error
}
guard let data = dataToReturn else {
XCTFail("dataToReturn n'est pas défini pour le MockNetworkClient.")
throw URLError(.unknown)
}
return data
}
}
// UserServiceIntegrationTests.swift (dans le target de test)
import XCTest
@testable import YourAppModule // Remplacez par le nom de votre module
class UserServiceIntegrationTests: XCTestCase {
var mockNetworkClient: MockNetworkClient!
var userService: UserService!
override func setUpWithError() throws {
mockNetworkClient = MockNetworkClient()
userService = UserService(networkClient: mockNetworkClient)
}
override func tearDownWithError() throws {
mockNetworkClient = nil
userService = nil
}
func testFetchUsers_Success() async throws {
let json = """
[
{"id": 1, "name": "Alice", "email": "[email protected]"},
{"id": 2, "name": "Bob", "email": "[email protected]"}
]
"""
mockNetworkClient.dataToReturn = json.data(using: .utf8)
let users = try await userService.fetchUsers()
XCTAssertEqual(users.count, 2)
XCTAssertEqual(users[0].name, "Alice")
XCTAssertEqual(mockNetworkClient.receivedURL?.absoluteString, "https://api.example.com/users")
}
func testFetchUsers_NetworkError() async {
mockNetworkClient.errorToThrow = URLError(.notConnectedToInternet)
do {
_ = try await userService.fetchUsers()
XCTFail("La récupération des utilisateurs devrait échouer avec une erreur réseau.")
} catch {
XCTAssertTrue(error is URLError)
let urlError = error as! URLError
XCTAssertEqual(urlError.code, .notConnectedToInternet)
}
}
}
Exemple de Test d’Intégration iOS (Swift – Service/NetworkClient)
EXPLICATION DU CODE
Ici, nous testons l’intégration entre un UserService et un NetworkClient. Le MockNetworkClient simule les réponses réseau, nous permettant de vérifier que le service gère correctement les données reçues sans effectuer de véritables appels réseau.
// User.swift
import Foundation
struct User: Codable, Equatable {
let id: Int
let name: String
let email: String
}
// NetworkClient.swift
import Foundation
protocol NetworkClient {
func fetchData(from url: URL) async throws -> Data
}
class URLSessionNetworkClient: NetworkClient {
func fetchData(from url: URL) async throws -> Data {
let (data, response) = try await URLSession.shared.data(from: url)
guard let httpResponse = response as? HTTPURLResponse, httpResponse.statusCode == 200 else {
throw URLError(.badServerResponse)
}
return data
}
}
// UserService.swift
import Foundation
class UserService {
private let networkClient: NetworkClient
private let usersURL = URL(string: "https://api.example.com/users")!
init(networkClient: NetworkClient) {
self.networkClient = networkClient
}
func fetchUsers() async throws -> [User] {
let data = try await networkClient.fetchData(from: usersURL)
let decoder = JSONDecoder()
return try decoder.decode([User].self, from: data)
}
}
// MockNetworkClient.swift (dans le target de test)
import Foundation
@testable import YourAppModule // Remplacez par le nom de votre module
class MockNetworkClient: NetworkClient {
var dataToReturn: Data?
var errorToThrow: Error?
var receivedURL: URL?
func fetchData(from url: URL) async throws -> Data {
receivedURL = url
if let error = errorToThrow {
throw error
}
guard let data = dataToReturn else {
XCTFail("dataToReturn n'est pas défini pour le MockNetworkClient.")
throw URLError(.unknown)
}
return data
}
}
// UserServiceIntegrationTests.swift (dans le target de test)
import XCTest
@testable import YourAppModule // Remplacez par le nom de votre module
class UserServiceIntegrationTests: XCTestCase {
var mockNetworkClient: MockNetworkClient!
var userService: UserService!
override func setUpWithError() throws {
mockNetworkClient = MockNetworkClient()
userService = UserService(networkClient: mockNetworkClient)
}
override func tearDownWithError() throws {
mockNetworkClient = nil
userService = nil
}
func testFetchUsers_Success() async throws {
let json = """
[
{"id": 1, "name": "Alice", "email": "[email protected]"},
{"id": 2, "name": "Bob", "email": "[email protected]"}
]
"""
mockNetworkClient.dataToReturn = json.data(using: .utf8)
let users = try await userService.fetchUsers()
XCTAssertEqual(users.count, 2)
XCTAssertEqual(users[0].name, "Alice")
XCTAssertEqual(mockNetworkClient.receivedURL?.absoluteString, "https://api.example.com/users")
}
func testFetchUsers_NetworkError() async {
mockNetworkClient.errorToThrow = URLError(.notConnectedToInternet)
do {
_ = try await userService.fetchUsers()
XCTFail("La récupération des utilisateurs devrait échouer avec une erreur réseau.")
} catch {
XCTAssertTrue(error is URLError)
let urlError = error as! URLError
XCTAssertEqual(urlError.code, .notConnectedToInternet)
}
}
}
Exemple de Test d’Intégration iOS (Swift – Service/NetworkClient)
EXPLICATION DU CODE
Ici, nous testons l’intégration entre un UserService et un NetworkClient. Le MockNetworkClient simule les réponses réseau, nous permettant de vérifier que le service gère correctement les données reçues sans effectuer de véritables appels réseau.
// User.swift
import Foundation
struct User: Codable, Equatable {
let id: Int
let name: String
let email: String
}
// NetworkClient.swift
import Foundation
protocol NetworkClient {
func fetchData(from url: URL) async throws -> Data
}
class URLSessionNetworkClient: NetworkClient {
func fetchData(from url: URL) async throws -> Data {
let (data, response) = try await URLSession.shared.data(from: url)
guard let httpResponse = response as? HTTPURLResponse, httpResponse.statusCode == 200 else {
throw URLError(.badServerResponse)
}
return data
}
}
// UserService.swift
import Foundation
class UserService {
private let networkClient: NetworkClient
private let usersURL = URL(string: "https://api.example.com/users")!
init(networkClient: NetworkClient) {
self.networkClient = networkClient
}
func fetchUsers() async throws -> [User] {
let data = try await networkClient.fetchData(from: usersURL)
let decoder = JSONDecoder()
return try decoder.decode([User].self, from: data)
}
}
// MockNetworkClient.swift (dans le target de test)
import Foundation
@testable import YourAppModule // Remplacez par le nom de votre module
class MockNetworkClient: NetworkClient {
var dataToReturn: Data?
var errorToThrow: Error?
var receivedURL: URL?
func fetchData(from url: URL) async throws -> Data {
receivedURL = url
if let error = errorToThrow {
throw error
}
guard let data = dataToReturn else {
XCTFail("dataToReturn n'est pas défini pour le MockNetworkClient.")
throw URLError(.unknown)
}
return data
}
}
// UserServiceIntegrationTests.swift (dans le target de test)
import XCTest
@testable import YourAppModule // Remplacez par le nom de votre module
class UserServiceIntegrationTests: XCTestCase {
var mockNetworkClient: MockNetworkClient!
var userService: UserService!
override func setUpWithError() throws {
mockNetworkClient = MockNetworkClient()
userService = UserService(networkClient: mockNetworkClient)
}
override func tearDownWithError() throws {
mockNetworkClient = nil
userService = nil
}
func testFetchUsers_Success() async throws {
let json = """
[
{"id": 1, "name": "Alice", "email": "[email protected]"},
{"id": 2, "name": "Bob", "email": "[email protected]"}
]
"""
mockNetworkClient.dataToReturn = json.data(using: .utf8)
let users = try await userService.fetchUsers()
XCTAssertEqual(users.count, 2)
XCTAssertEqual(users[0].name, "Alice")
XCTAssertEqual(mockNetworkClient.receivedURL?.absoluteString, "https://api.example.com/users")
}
func testFetchUsers_NetworkError() async {
mockNetworkClient.errorToThrow = URLError(.notConnectedToInternet)
do {
_ = try await userService.fetchUsers()
XCTFail("La récupération des utilisateurs devrait échouer avec une erreur réseau.")
} catch {
XCTAssertTrue(error is URLError)
let urlError = error as! URLError
XCTAssertEqual(urlError.code, .notConnectedToInternet)
}
}
}
Exemple de Test d’Intégration iOS (Swift – Service/NetworkClient)
EXPLICATION DU CODE
Ici, nous testons l’intégration entre un UserService et un NetworkClient. Le MockNetworkClient simule les réponses réseau, nous permettant de vérifier que le service gère correctement les données reçues sans effectuer de véritables appels réseau.
// User.swift
import Foundation
struct User: Codable, Equatable {
let id: Int
let name: String
let email: String
}
// NetworkClient.swift
import Foundation
protocol NetworkClient {
func fetchData(from url: URL) async throws -> Data
}
class URLSessionNetworkClient: NetworkClient {
func fetchData(from url: URL) async throws -> Data {
let (data, response) = try await URLSession.shared.data(from: url)
guard let httpResponse = response as? HTTPURLResponse, httpResponse.statusCode == 200 else {
throw URLError(.badServerResponse)
}
return data
}
}
// UserService.swift
import Foundation
class UserService {
private let networkClient: NetworkClient
private let usersURL = URL(string: "https://api.example.com/users")!
init(networkClient: NetworkClient) {
self.networkClient = networkClient
}
func fetchUsers() async throws -> [User] {
let data = try await networkClient.fetchData(from: usersURL)
let decoder = JSONDecoder()
return try decoder.decode([User].self, from: data)
}
}
// MockNetworkClient.swift (dans le target de test)
import Foundation
@testable import YourAppModule // Remplacez par le nom de votre module
class MockNetworkClient: NetworkClient {
var dataToReturn: Data?
var errorToThrow: Error?
var receivedURL: URL?
func fetchData(from url: URL) async throws -> Data {
receivedURL = url
if let error = errorToThrow {
throw error
}
guard let data = dataToReturn else {
XCTFail("dataToReturn n'est pas défini pour le MockNetworkClient.")
throw URLError(.unknown)
}
return data
}
}
// UserServiceIntegrationTests.swift (dans le target de test)
import XCTest
@testable import YourAppModule // Remplacez par le nom de votre module
class UserServiceIntegrationTests: XCTestCase {
var mockNetworkClient: MockNetworkClient!
var userService: UserService!
override func setUpWithError() throws {
mockNetworkClient = MockNetworkClient()
userService = UserService(networkClient: mockNetworkClient)
}
override func tearDownWithError() throws {
mockNetworkClient = nil
userService = nil
}
func testFetchUsers_Success() async throws {
let json = """
[
{"id": 1, "name": "Alice", "email": "[email protected]"},
{"id": 2, "name": "Bob", "email": "[email protected]"}
]
"""
mockNetworkClient.dataToReturn = json.data(using: .utf8)
let users = try await userService.fetchUsers()
XCTAssertEqual(users.count, 2)
XCTAssertEqual(users[0].name, "Alice")
XCTAssertEqual(mockNetworkClient.receivedURL?.absoluteString, "https://api.example.com/users")
}
func testFetchUsers_NetworkError() async {
mockNetworkClient.errorToThrow = URLError(.notConnectedToInternet)
do {
_ = try await userService.fetchUsers()
XCTFail("La récupération des utilisateurs devrait échouer avec une erreur réseau.")
} catch {
XCTAssertTrue(error is URLError)
let urlError = error as! URLError
XCTAssertEqual(urlError.code, .notConnectedToInternet)
}
}
}
Exemple de Test d’Intégration iOS (Swift – Service/NetworkClient)
EXPLICATION DU CODE
Ici, nous testons l’intégration entre un UserService et un NetworkClient. Le MockNetworkClient simule les réponses réseau, nous permettant de vérifier que le service gère correctement les données reçues sans effectuer de véritables appels réseau.
// User.swift
import Foundation
struct User: Codable, Equatable {
let id: Int
let name: String
let email: String
}
// NetworkClient.swift
import Foundation
protocol NetworkClient {
func fetchData(from url: URL) async throws -> Data
}
class URLSessionNetworkClient: NetworkClient {
func fetchData(from url: URL) async throws -> Data {
let (data, response) = try await URLSession.shared.data(from: url)
guard let httpResponse = response as? HTTPURLResponse, httpResponse.statusCode == 200 else {
throw URLError(.badServerResponse)
}
return data
}
}
// UserService.swift
import Foundation
class UserService {
private let networkClient: NetworkClient
private let usersURL = URL(string: "https://api.example.com/users")!
init(networkClient: NetworkClient) {
self.networkClient = networkClient
}
func fetchUsers() async throws -> [User] {
let data = try await networkClient.fetchData(from: usersURL)
let decoder = JSONDecoder()
return try decoder.decode([User].self, from: data)
}
}
// MockNetworkClient.swift (dans le target de test)
import Foundation
@testable import YourAppModule // Remplacez par le nom de votre module
class MockNetworkClient: NetworkClient {
var dataToReturn: Data?
var errorToThrow: Error?
var receivedURL: URL?
func fetchData(from url: URL) async throws -> Data {
receivedURL = url
if let error = errorToThrow {
throw error
}
guard let data = dataToReturn else {
XCTFail("dataToReturn n'est pas défini pour le MockNetworkClient.")
throw URLError(.unknown)
}
return data
}
}
// UserServiceIntegrationTests.swift (dans le target de test)
import XCTest
@testable import YourAppModule // Remplacez par le nom de votre module
class UserServiceIntegrationTests: XCTestCase {
var mockNetworkClient: MockNetworkClient!
var userService: UserService!
override func setUpWithError() throws {
mockNetworkClient = MockNetworkClient()
userService = UserService(networkClient: mockNetworkClient)
}
override func tearDownWithError() throws {
mockNetworkClient = nil
userService = nil
}
func testFetchUsers_Success() async throws {
let json = """
[
{"id": 1, "name": "Alice", "email": "[email protected]"},
{"id": 2, "name": "Bob", "email": "[email protected]"}
]
"""
mockNetworkClient.dataToReturn = json.data(using: .utf8)
let users = try await userService.fetchUsers()
XCTAssertEqual(users.count, 2)
XCTAssertEqual(users[0].name, "Alice")
XCTAssertEqual(mockNetworkClient.receivedURL?.absoluteString, "https://api.example.com/users")
}
func testFetchUsers_NetworkError() async {
mockNetworkClient.errorToThrow = URLError(.notConnectedToInternet)
do {
_ = try await userService.fetchUsers()
XCTFail("La récupération des utilisateurs devrait échouer avec une erreur réseau.")
} catch {
XCTAssertTrue(error is URLError)
let urlError = error as! URLError
XCTAssertEqual(urlError.code, .notConnectedToInternet)
}
}
}
Exemple de Test d’Intégration iOS (Swift – Service/NetworkClient)
EXPLICATION DU CODE
Ici, nous testons l’intégration entre un UserService et un NetworkClient. Le MockNetworkClient simule les réponses réseau, nous permettant de vérifier que le service gère correctement les données reçues sans effectuer de véritables appels réseau.
// User.swift
import Foundation
struct User: Codable, Equatable {
let id: Int
let name: String
let email: String
}
// NetworkClient.swift
import Foundation
protocol NetworkClient {
func fetchData(from url: URL) async throws -> Data
}
class URLSessionNetworkClient: NetworkClient {
func fetchData(from url: URL) async throws -> Data {
let (data, response) = try await URLSession.shared.data(from: url)
guard let httpResponse = response as? HTTPURLResponse, httpResponse.statusCode == 200 else {
throw URLError(.badServerResponse)
}
return data
}
}
// UserService.swift
import Foundation
class UserService {
private let networkClient: NetworkClient
private let usersURL = URL(string: "https://api.example.com/users")!
init(networkClient: NetworkClient) {
self.networkClient = networkClient
}
func fetchUsers() async throws -> [User] {
let data = try await networkClient.fetchData(from: usersURL)
let decoder = JSONDecoder()
return try decoder.decode([User].self, from: data)
}
}
// MockNetworkClient.swift (dans le target de test)
import Foundation
@testable import YourAppModule // Remplacez par le nom de votre module
class MockNetworkClient: NetworkClient {
var dataToReturn: Data?
var errorToThrow: Error?
var receivedURL: URL?
func fetchData(from url: URL) async throws -> Data {
receivedURL = url
if let error = errorToThrow {
throw error
}
guard let data = dataToReturn else {
XCTFail("dataToReturn n'est pas défini pour le MockNetworkClient.")
throw URLError(.unknown)
}
return data
}
}
// UserServiceIntegrationTests.swift (dans le target de test)
import XCTest
@testable import YourAppModule // Remplacez par le nom de votre module
class UserServiceIntegrationTests: XCTestCase {
var mockNetworkClient: MockNetworkClient!
var userService: UserService!
override func setUpWithError() throws {
mockNetworkClient = MockNetworkClient()
userService = UserService(networkClient: mockNetworkClient)
}
override func tearDownWithError() throws {
mockNetworkClient = nil
userService = nil
}
func testFetchUsers_Success() async throws {
let json = """
[
{"id": 1, "name": "Alice", "email": "[email protected]"},
{"id": 2, "name": "Bob", "email": "[email protected]"}
]
"""
mockNetworkClient.dataToReturn = json.data(using: .utf8)
let users = try await userService.fetchUsers()
XCTAssertEqual(users.count, 2)
XCTAssertEqual(users[0].name, "Alice")
XCTAssertEqual(mockNetworkClient.receivedURL?.absoluteString, "https://api.example.com/users")
}
func testFetchUsers_NetworkError() async {
mockNetworkClient.errorToThrow = URLError(.notConnectedToInternet)
do {
_ = try await userService.fetchUsers()
XCTFail("La récupération des utilisateurs devrait échouer avec une erreur réseau.")
} catch {
XCTAssertTrue(error is URLError)
let urlError = error as! URLError
XCTAssertEqual(urlError.code, .notConnectedToInternet)
}
}
}
Exemple de Test d’Intégration iOS (Swift – Service/NetworkClient)
EXPLICATION DU CODE
Ici, nous testons l’intégration entre un UserService et un NetworkClient. Le MockNetworkClient simule les réponses réseau, nous permettant de vérifier que le service gère correctement les données reçues sans effectuer de véritables appels réseau.
// User.swift
import Foundation
struct User: Codable, Equatable {
let id: Int
let name: String
let email: String
}
// NetworkClient.swift
import Foundation
protocol NetworkClient {
func fetchData(from url: URL) async throws -> Data
}
class URLSessionNetworkClient: NetworkClient {
func fetchData(from url: URL) async throws -> Data {
let (data, response) = try await URLSession.shared.data(from: url)
guard let httpResponse = response as? HTTPURLResponse, httpResponse.statusCode == 200 else {
throw URLError(.badServerResponse)
}
return data
}
}
// UserService.swift
import Foundation
class UserService {
private let networkClient: NetworkClient
private let usersURL = URL(string: "https://api.example.com/users")!
init(networkClient: NetworkClient) {
self.networkClient = networkClient
}
func fetchUsers() async throws -> [User] {
let data = try await networkClient.fetchData(from: usersURL)
let decoder = JSONDecoder()
return try decoder.decode([User].self, from: data)
}
}
// MockNetworkClient.swift (dans le target de test)
import Foundation
@testable import YourAppModule // Remplacez par le nom de votre module
class MockNetworkClient: NetworkClient {
var dataToReturn: Data?
var errorToThrow: Error?
var receivedURL: URL?
func fetchData(from url: URL) async throws -> Data {
receivedURL = url
if let error = errorToThrow {
throw error
}
guard let data = dataToReturn else {
XCTFail("dataToReturn n'est pas défini pour le MockNetworkClient.")
throw URLError(.unknown)
}
return data
}
}
// UserServiceIntegrationTests.swift (dans le target de test)
import XCTest
@testable import YourAppModule // Remplacez par le nom de votre module
class UserServiceIntegrationTests: XCTestCase {
var mockNetworkClient: MockNetworkClient!
var userService: UserService!
override func setUpWithError() throws {
mockNetworkClient = MockNetworkClient()
userService = UserService(networkClient: mockNetworkClient)
}
override func tearDownWithError() throws {
mockNetworkClient = nil
userService = nil
}
func testFetchUsers_Success() async throws {
let json = """
[
{"id": 1, "name": "Alice", "email": "[email protected]"},
{"id": 2, "name": "Bob", "email": "[email protected]"}
]
"""
mockNetworkClient.dataToReturn = json.data(using: .utf8)
let users = try await userService.fetchUsers()
XCTAssertEqual(users.count, 2)
XCTAssertEqual(users[0].name, "Alice")
XCTAssertEqual(mockNetworkClient.receivedURL?.absoluteString, "https://api.example.com/users")
}
func testFetchUsers_NetworkError() async {
mockNetworkClient.errorToThrow = URLError(.notConnectedToInternet)
do {
_ = try await userService.fetchUsers()
XCTFail("La récupération des utilisateurs devrait échouer avec une erreur réseau.")
} catch {
XCTAssertTrue(error is URLError)
let urlError = error as! URLError
XCTAssertEqual(urlError.code, .notConnectedToInternet)
}
}
}
Exemple de Test d’Intégration iOS (Swift – Service/NetworkClient)
EXPLICATION DU CODE
Ici, nous testons l’intégration entre un UserService et un NetworkClient. Le MockNetworkClient simule les réponses réseau, nous permettant de vérifier que le service gère correctement les données reçues sans effectuer de véritables appels réseau.
// User.swift
import Foundationstruct User: Codable, Equatable {
let id: Int
let name: String
let email: String
}
// NetworkClient.swift
import Foundation
protocol NetworkClient {
func fetchData(from url: URL) async throws -> Data
}
class URLSessionNetworkClient: NetworkClient {
func fetchData(from url: URL) async throws -> Data {
let (data, response) = try await URLSession.shared.data(from: url)
guard let httpResponse = response as? HTTPURLResponse, httpResponse.statusCode == 200 else {
throw URLError(.badServerResponse)
}
return data
}
}
// UserService.swift
import Foundation
class UserService {