Fake (feyk) — işləyən sadələşdirilmiş asılılıq implementasiyasıdır, əsl komponent kimi davranır, lakin istehsal infrastrukturu əvəzinə in-memory yaddaş və ya digər yüngül mexanizmlərdən istifadə edir. Stub-dan fərqli olaraq, fake real biznes məntiqi ehtiva edir — sıralama, filtrləmə, aqreqasiya — sadəcə xarici effektlər olmadan. Room əvəzinə in-memory verilənlər bazası və ya SharedPreferences əvəzinə HashMap — klassik nümunələr. Ətraflı Martin Fowler-in test doubles təsnifatında.
Başlıca
Fake — testləşdirmə üçün uyğun olan tamhüquqlu, lakin yüngül interfeys implementasiyasıdır. Termin Gerard Meszaros (2007) tərəfindən «xUnit Test Patterns» kitabında təqdim edilmişdir. Sərt şəkildə müəyyən edilmiş cavabları qaytaran stub-dan fərqli olaraq, fake icra olunan kodu ehtiva edir: siyahını sıralaya, şərt üzrə filtrləyə, yazıların sayını hesablaya bilər. İstehsal implementasiyasından yeganə fərq — fake in-memory məlumatlarla işləyir və real I/O əməliyyatları yerinə yetirmir.
Əsas üstünlük — sürətdir. Fake ilə testlər milisaniyələr ərzində yerinə yetirilir, çünki diskə, şəbəkəyə və ya verilənlər bazasına müraciət yoxdur. In-memory HashMap Room və ya CoreData-dan 100-1000 dəfə sürətli işləyir. Eyni zamanda fake real biznes məntiqini yoxlayır: sıralama, filtrləmə, aqreqasiya — stub-un yoxlaya bilmədiyi hər şey, çünki stub yalnız ona deyiləni qaytarır. Fake kodun məlumatları düzgün emal etdiyinə əminlik verir, sadəcə əvvəlcədən müəyyən edilmiş cavabı almır.
Fake Stub-dan üstündür — əgər test edilən komponent məlumatlar üzərində bir neçə əməliyyat yerinə yetirirsə (çıxardı, filtrlədi, sıraladı, saxladı), stub hər çağırışın ayrıca konfiqurasiyasını tələb edəcək. Fake məntiqi öz daxilində saxlayır — test sadəcə metodları çağırır və nəticəni yoxlayır. IT Sectr-də biz vahid testlərdə bütün repozitoriyalar üçün fake-dan istifadə edirik: HashMap ilə fake-repozitoriya Mockito və ya MockK konfiqurasiyası olmadan 90% ssenariləri əhatə edir.
Seçim meyarı — testin nəyi yoxladığını müəyyən edin: vəziyyəti və ya qarşılıqlı əlaqəni. Əgər test vəziyyəti (işin nəticəsini) yoxlayırsa və məntiqdən istifadə edirsə — fake lazımdır. Əgər testə yalnız məntiqsiz giriş məlumatları lazımdırsa — stub kifayətdir. Əgər test metodun çağırılma faktını yoxlayırsa — mock lazımdır. Bir testdə test doubles növlərinin qarışdırılması anlaşmanı çətinləşdirir və kövrəkliyi artırır.
| Meyar | Fake | Stub | Mock |
|---|---|---|---|
| Məntiqin olması | Bəli (sadələşdirilmiş) | Xeyr | Xeyr |
| Sürət | Yüksək | Maksimal | Yüksək |
| Davranışın yoxlanılması | Dolaylı | Xeyr | Bəli (verify) |
| Baxım | Hər interfeys üçün bir sinif | Hər test üçün konfiqurasiya | Hər test üçün konfiqurasiya |
| Reallıq | Yüksək (kod işləyir) | Aşağı (sərt məlumatlar) | Orta |
| Yalan pozitiv riski | Aşağı | Orta | Yüksək (kövrək testlər) |
Anti-nümunə: Fake olmayan Fake — proqramçının əslində stub və ya mock olan obyekti fake adlandırması geniş yayılmış səhvdir. Əgər InMemoryUserRepository məntiq (filtrləmə, sıralama) ehtiva etmirsə — bu fake deyil, in-memory saxlama ilə stub-dur. Fake stub-dan məhz icra olunan məntiqə malik olması ilə fərqlənir. Əgər fake-repozitoriya sadəcə içinə qoyulanı qaytarırsa və məlumatları emal etmirsə — mock və ya stub istifadə edin.
Praktiki tövsiyə — hər repozitoriya və ya xidmət üçün fake ilə başlayın. Əgər fake 50 sətirdən mürəkkəbdirsə — bir neçə sinfə bölün. Əgər fake ümumiyyətlə lazım deyilsə (test yalnız bir ssenarini sabit məlumatlarla yoxlayır) — stub istifadə edin. Əgər test metodun müəyyən parametrlərlə çağırıldığını yoxlayırsa — mock istifadə edin. Seçimi əvvəlcədən optimallaşdırmayın: fake yazın, əgər artıq olarsa, konkret testdə onu stub ilə əvəz edin.
Room üçün Fake-repozitoriya — Android-də fake-ın tipik nümunəsi. İstehsal UserRepository implementasiyası SQLite sorğuları ilə Room DAO-dan istifadə edir. Fake versiyası məlumatları MutableList və ya HashMap-də saxlayır və eyni metodları implementasiya edir: getUser(id), saveUser(user), deleteUser(id). Fake eyni axtarış, filtrləmə və sıralama məntiqini ehtiva edir — istehsal repozitoriyası kimi, lakin SQL olmadan. Bu, Room bazasını konfiqurasiya etmədən ViewModel və UseCase-ı test etməyə imkan verir.
class FakeUserRepository : UserRepository {
private val users = mutableListOf<User>()
override suspend fun getUser(id: String): User? {
return users.find { it.id == id }
}
override suspend fun saveUser(user: User) {
val index = users.indexOfFirst { it.id == user.id }
if (index >= 0) users[index] = user
else users.add(user)
}
override suspend fun search(query: String): List<User> {
return users.filter {
it.name.contains(query, ignoreCase = true)
}
}
}
Retrofit API üçün Fake — MockWebServer (ɟəsillişdirilmiş) əvəzinə in-memory kolleksiyadan məlumatları qaytaran ApiService implementasiyası yaradıla bilər. Fərq: MockWebServer HTTP-ni tutur və JSON qaytarır, fake-ApiService isə serializasiya olmadan Kotlin interfeysi səviyyəsində işləyir. Fake daha sürətlidir (JSON parsingsiz) və sazlamada daha sadədir (eyni prosesdə işləyir, tipləşdirilmişdir). HTTP semantikasının (əsas kodları, başlıqlar) vacib olmadığı testlər üçün uyğundur.
Swift-də Fake — protokollar vasitəsilə qurulur. İstehsal sinfi real məntiqlə (CoreData, URLSession) protokolu implementasiya edir. Fake strukturu eyni protokolu in-memory yaddaş və sadələşdirilmiş məntiqlə implementasiya edir. Swift dəyər semantikasına malik dildir, buna görə fake strukturları dəyişməz və çoxiplikli testlərdə təhlükəsizdir. Bu, Android analoqları üzərində üstünlük verir: in-memory məlumatlara girişi sinxronlaşdırmağa ehtiyac yoxdur.
protocol UserRepositoryProtocol {
func getUser(id: String) async -> User?
func saveUser(user: User) async
}
final class FakeUserRepository: UserRepositoryProtocol {
private var storage: [String: User] = [:]
func getUser(id: String) async -> User? {
return storage[id]
}
func saveUser(user: User) async {
storage[user.id] = user
}
}
final class UserViewModelTests: XCTestCase {
func test_save_and_load() async {
let fake = FakeUserRepository()
let vm = UserViewModel(repository: fake)
let user = User(id: "1", name: "Alice")
await vm.saveUser(user)
let loaded = await vm.getUser(id: "1")
XCTAssertEqual(loaded?.name, "Alice")
}
}
CoreData üçün Fake — iOS layihələrində description.type = NSInMemoryStoreType göstərməklə in-memory NSPersistentContainer yaradıla bilər. Bu, tamhüquqlu CoreData stack-ıdır, lakin yaddaşda işləyir. Belə fake SQLite faylı yaratmadan NSFetchRequest, predikatlar və sıralamaları test etməyə imkan verir. Sürət: in-memory CoreData testləri disk analoqundan 5-10 dəfə sürətli yerinə yetirilir. Çatışmazlıq: hər dəfə NSManagedObjectModel konfiqurasiya etmək lazımdır.
FakeURLProtocol — iOS-da şəbəkə sorğularını tutmaq üçün URLProtocol alt sinfi. URLProtocol.registerClass(fakeProtocol) vasitəsilə qeydiyyatdan keçir. Daxilində URL -> Data in-memory lüğəti saxlayır və real sorğu olmadan məlumatları qaytarır. Stub-dan fərqi: FakeURLProtocol sorğun gövdəsini, başlıqları yoxlaya və giriş məlumatlarından asılı olaraq müxtəlif cavablar qaytara bilər. Bu fake-dır, çünki sorğu marşrutlaşdırma məntiqini ehtiva edir.
Test Fixture kimi Fake — fake siniflərini ümumi test moduluna (çıxarın (androidTest/sharedTest və ya TestSupport). Layihədəki bütün testlər eyni InMemoryUserRepository-dən istifadə edir. Bu, hər testdə mock obyektlərinin konfiqurasiyasının təkrarlanmasını aradan qaldırır və vahid davranışı təmin edir. Fake məntiqinin dəyişməsi bütün testləri eyni anda yeniləyir. IT Sectr-də biz fake siniflərini sharedTest/java/com/itSectr/fake/ şəklində saxlayır və implementation project(:sharedTest) vasitƏlsilə qoşur.
Öncədən qurulmuş məlumatlarla Fake — tez-tez testlər artıq müəyyən yazıları olan repozitoriya tələb edir. Həll: fakeWithData(vararg items) fabrik metodu və ya daxili addDefaultData() metodu. Fabrik fake yaradır, onu tipik məlumatlarla doldurur və istifadəyə hazır obyekti qaytarır. Bu, testlərdə boilerplate-ı azaldır: mock çağırışlarını konfiqurasiya etmək əvəzinə test sadəcə FakeUserRepository.withUsers(alice, bob) çağırır.
Çağırış sayı ilə Fake — bəzən təkcə vəziyyəti deyil, həm də müraciətlərin sayını yoxlamaq lazımdır. Fake sayıcılar ehtiva edə bilər: saveCallCount, getUserCallCount. Test icradan sonra sayıcını yoxlayır. Bu, təmiz fake (vəziyyətin yoxlanılması) ilə mock (qarşılıqlı əlaqənin yoxlanılması) arasında kompromisdir. Sayıcılar arqumentləri və çağırış ardıcıllığını yoxlamır — yalnız sayı. Arqumentləri yoxlamaq üçün mock istifadə edin.
Callback ilə Fake — asinxron ssenariləri test etmək üçün fake hər çağırışda callback qəbul edə bilər: beforeGetUser, afterSaveUser. Bu, gecikmələri, səhvləri simulyasiya etməyə və ya aralıq vəziyyətləri yoxlamağa imkan verir. Belə yanaşma UI-nin yüklənmə vəziyyətlərini test etmək üçün faydalıdır: fake 100 ms fasilə edir, test isə ekranın yükləyicini göstərdiyini yoxlayır. İstehsal mühitində callback yoxdur — bu sırf test funksionallığıdır.
Tez-tez verilən suallar
Fake işləyən məntiq ehtiva edir — filtrləyir, sıralayır, hesablayır. Stub yalnız əvvəlcədən müəyyən edilmiş cavabları məntiqsiz qaytarır. Əgər obyektin budaqlanması varsa (if/else, when) — bu fake-dır. Əgər yalnız return values ehtiva edirsə — bu stub-dur. Fake daha bahalıdır, lakin daha realist testlər verir.
Fake məntiqi istehsal məntiqi ilə üst-üstə düşmədikdə. Məsələn, FakeUserRepository case-sensitive axtarışdan istifadə edir, istehsal isə case-insensitive. Test keçir, amma realda səhv var. Həll: fake məntiqini ayrıca test edin və ya fake-ləri yalnız sadə məntiqi olan interfeyslər üçün istifadə edin (CRUD əməliyyatları). Mürəkkəb məntiq üçün real verilənlər bazası ilə inteqrasiya testləri yazın.
In-memory database — fake-ın variantlarından biridir. Room.inMemoryDatabaseBuilder() istehsal bazası kimi davranan in-memory SQLite yaradır. Bu tamhüquqlu fake-dır. Lakin fake həm repozitoriya səviyyəsində (SQL olmadan), həm də şəbəkə səviyyəsində (FakeApiService) ola bilər. In-memory verilənlər bazası — fake-ın xüsusi halıdır, məntiq maksimum dərəcədə reala yaxındır.
Bəli, lakin ehtiyatla. Fake repozitoriya üçün (məlumatlar), Mock AnalyticsTracker üçün (hadisələrin yoxlanılması). Qatlara görə bölgü: fake məlumat qatı üçün, mock analitika/jurnal qatı üçün. Bir obyekti eyni anda fake və mock etməyin — bu Tək Məsuliyyət Prinsipini pozur və testi çətinləşdirir.
Fake-ı test edin istehsal implementasiyası ilə eyni testlərlə. Əgər save, get, delete-i yoxlayan UserRepositoryTest varsa — onu iki dəfə işə salın: FakeUserRepository və RealUserRepository ilə. Bu, fake-ın istehsal sinfinin davranışını təkrarladığını təmin edir. Əgər fake fərqli davranmağa başlayarsa — test hər iki implementasiyada uğursuz olacaq.
Nəticələr
Açar təslim mobil tətbiq hazırlayacağıq
IT Sectr 2017-ci ildən startaplar və bizneslər üçün iOS və Android tətbiqləri yaradır. Sizə məsləhət verəcəyik və ən yaxşı həlli təklif edəcəyik.
Həm də oxuyun