Fake gerçek bir bileşen gibi davranan ancak üretim altyapısı yerine bellek içi depolama veya diğer hafif mekanizmaları kullanan bir bağımlılığın çalışan basitleştirilmiş uygulamasıdır. Stub'ın aksine, fake gerçek iş mantığı içerir — sıralama, filtreleme, toplama — ancak dış etkiler olmadan. Room yerine bellek içi veritabanı veya SharedPreferences yerine HashMap klasik örneklerdir. Daha fazla ayrıntı için Martin Fowler'ın test double sınıflandırmasına bakın.
Anahtar Noktalar
Fake, test için uygun, bir arayüzün tam ancak hafif bir uygulamasıdır. Terim Gerard Meszaros (2007) tarafından “xUnit Test Patterns” kitabında tanıtılmıştır. Sabit kodlanmış yanıtlar döndüren stub'ın aksine, fake çalıştırılabilir kod içerir: bir listeyi sıralayabilir, koşula göre filtreleyebilir, kayıtları sayabilir. Üretim uygulamasından tek farkı, fake'in bellek içi verilerle çalışması ve gerçek G/Ç işlemleri gerçekleştirmemesidir.
Ana avantajı hızdır. Fake ile testler milisaniyeler içinde çalışır çünkü diske, ağa veya veritabanına erişim yoktur. Bellek içi bir HashMap, Room veya CoreData'dan 100–1000 kat daha hızlı çalışır. Aynı zamanda, fake gerçek iş mantığını test eder: sıralama, filtreleme, toplama — stub'ın test edemeyeceği her şey, çünkü stub yalnızca kendisine söyleneni döndürür. Fake, kodun önceden belirlenmiş bir yanıt almak yerine verileri doğru şekilde işlediği konusunda güven verir.
Fake, Stub'a tercih edilir — test edilen bileşen veriler üzerinde birden çok işlem gerçekleştiriyorsa (alma, filtreleme, sıralama, kaydetme), stub her çağrıyı ayrı ayrı yapılandırmayı gerektirir. Fake, mantığı kendi içinde barındırır — test basitçe yöntemleri çağırır ve sonucu kontrol eder. IT Sectr'da, birim testlerinde tüm depolar için fakes kullanırız: HashMap ile bir fake depo, Mockito veya MockK yapılandırmadan senaryoların %90'ını kapsar.
Seçim kriteri — testin neyi doğruladığını belirleyin: durum mu yoksa etkileşim mi. Test durumu (çalışmanın sonucu) doğruluyor ve mantık kullanıyorsa — fake kullanın. Testin yalnızca mantıksız girdi verisine ihtiyacı varsa — stub yeterlidir. Test bir yöntemin çağrıldığını doğruluyorsa — mock kullanın. Bir testte test double türlerini karıştırmak anlaşılmayı zorlaştırır ve kırılganlığı artırır.
| Kriter | Fake | Stub | Mock |
|---|---|---|---|
| Mantığı var | Evet (basitleştirilmiş) | Hayır | Hayır |
| Hız | Yüksek | Maksimum | Yüksek |
| Davranış doğrulama | Dolaylı | Hayır | Evet (verify) |
| Bakım | Arayüz başına bir sınıf | Test başına yapılandır | Test başına yapılandır |
| Gerçekçilik | Yüksek (kod çalışır) | Düşük (sabit veri) | Orta |
| Yanlış pozitif riski | Düşük | Orta | Yüksek (kırılgan testler) |
Anti-kalıp: Fake olmayan fake — bir geliştiricinin aslında stub veya mock olan bir nesneye fake demesi yaygın bir hatadır. InMemoryUserRepository'iniz mantık (filtreleme, sıralama) içermiyorsa — bu fake değil, bellek içi depolamalı bir stub'dır. Fake, stub'dan tam olarak çalıştırılabilir mantığa sahip olmasıyla ayrılır. Bir fake depo yalnızca içine konulanı döndürüyor ve verileri işlemiyorsa — mock veya stub kullanın.
Pratik öneri — her depo veya hizmet için bir fake ile başlayın. Bir fake 50 satırı aşarsa — birkaç sınıfa bölün. Fake hiç gerekli değilse (test yalnızca sabit verili tek bir senaryoyu doğruluyorsa) — stub kullanın. Test bir yöntemin belirli parametrelerle çağrıldığını doğruluyorsa — mock kullanın. Seçimi önceden optimize etmeyin: bir fake yazın ve aşırı olduğu ortaya çıkarsa, belirli bir testte onu bir stub ile değiştirin.
Room için Fake depo — Android'de tipik bir fake örneği. UserRepository'nin üretim uygulaması SQLite sorgularıyla Room DAO kullanır. Fake sürüm, verileri bir MutableList veya HashMap'te saklar ve aynı yöntemleri uygular: getUser(id), saveUser(user), deleteUser(id). Fake, arama, filtreleme ve sıralama mantığı içerir — üretim deposuyla aynı, ancak SQL olmadan. Bu, Room veritabanı kurmadan ViewModel ve UseCase'i test etmeyi sağlar.
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 için Fake — MockWebServer (bir stub'dır, fake değildir) yerine, bellek içi bir koleksiyondan veri döndüren bir ApiService uygulaması oluşturabilirsiniz. Farkı: MockWebServer HTTP'yi keser ve JSON döndürürken, fake ApiService serileştirme olmadan Kotlin arayüzü düzeyinde çalışır. Fake daha hızlıdır (JSON ayrıştırma yok) ve hata ayıklaması daha kolaydır (aynı süreçte çalışır, tür belirtilmiş). HTTP anlambiliminin (durum kodları, başlıklar) önemli olmadığı testler için uygundur.
Swift'te Fake — protokoller aracılığıyla oluşturulur. Üretim sınıfı, protokolü gerçek mantıkla (CoreData, URLSession) uygular. Fake yapısı, aynı protokolü bellek içi depolama ve basitleştirilmiş mantıkla uygular. Swift, değer anlambilimine sahip bir dildir, bu nedenle fake yapıları değiştirilemez ve çok iç parçacıklı testlerde güvenlidir. Bu, Android benzerlerine göre bir avantaj sağlar: bellek içi verilere erişimi senkronize etmeye gerek yoktur.
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 için Fake — iOS projelerinde, description.type = NSInMemoryStoreType ayarını yaparak bellek içi bir NSPersistentContainer oluşturabilirsiniz. Bu, tam bir CoreData yığınıdır ancak bellekte çalışır. Böyle bir fake, SQLite dosyası oluşturmadan NSFetchRequest, koşullar ve sıralamaları test etmeye olanak tanır. Hız: bellek içi CoreData'daki testler, disk tabanlı benzerinden 5–10 kat daha hızlı çalışır. Dezavantajı: her seferinde NSManagedObjectModel kurulumu gerektirir.
FakeURLProtocol — iOS'ta ağ isteklerini kesmek için URLProtocol'un bir alt sınıfıdır. URLProtocol.registerClass(fakeProtocol) aracılığıyla kaydedilir. Dahili olarak bellek içi bir URL -> Data sözlüğü içerir ve gerçek istek olmadan veri döndürür. Stub'dan farkı: FakeURLProtocol istek gövdesini, başlıkları kontrol edebilir ve girdi verilerine bağlı olarak farklı yanıtlar döndürebilir. İstek yönlendirme mantığı içerdiği için bu bir fake'tir.
Test Fixture olarak Fake — fake sınıflarını paylaşılan bir test modülüne (androidTest/sharedTest veya TestSupport) koyun. Projedeki tüm testler aynı InMemoryUserRepository'yi kullanır. Bu, her testte mock nesne kurulumunun tekrarını ortadan kaldırır ve tek tip davranışı garanti eder. Fake mantığını değiştirmek tüm testleri aynı anda günceller. IT Sectr'da, fake sınıflarını sharedTest/java/com/itSectr/fake/ içinde saklıyoruz ve bunları implementation project(:sharedTest) aracılığıyla dahil ediyoruz.
Önceden ayarlanmış verilerle Fake — testler genellikle zaten bazı kayıtları içeren bir depoya ihtiyaç duyar. Çözüm: bir fabrika yöntemi fakeWithData(vararg items) veya yerleşik bir addDefaultData() yöntemi. Fabrika bir fake oluşturur, tipik verilerle doldurur ve kullanıma hazır bir nesne döndürür. Bu, testlerdeki tekrarı azaltır: mock çağrılarını ayarlamak yerine, test basitçe FakeUserRepository.withUsers(alice, bob) çağrısını yapar.
Çağrı sayma ile Fake — bazen yalnızca durumu değil, aynı zamanda çağrı sayısını da doğrulamak gerekir. Fake, sayaçlar içerebilir: saveCallCount, getUserCallCount. Test, çalıştırmadan sonra sayacı kontrol eder. Bu, saf fake (durum doğrulama) ile mock (etkileşim doğrulama) arasında bir uzlaşıdır. Sayaçlar, bağımsız değişkenleri veya çağrı sırasını kontrol etmez — yalnızca sayıyı kontrol eder. Bağımsız değişken doğrulaması için mock kullanın.
Callback ile Fake — eş zamansız senaryoları test etmek için fake, her çağrıda bir callback kabul edebilir: beforeGetUser, afterSaveUser. Bu, gecikmeleri, hataları simüle etmeye veya ara durumları kontrol etmeye olanak tanır. Bu yaklaşım, UI yükleme durumlarını test etmek için kullanışlıdır: fake 100 ms duraklatır ve test, ekranın bir yükleyici gösterdiğini doğrular. Callback üretimde yoktur — bu tamamen test işlevselliğidir.
Sıkça Sorulan Sorular
Fake işlevsel mantık içerir — filtreler, sıralar, sayar. Stub, mantıksız yalnızca önceden belirlenmiş yanıtlar döndürür. Bir nesnenin dallanmaları (if/else, when) varsa — bu fake'tir. Yalnızca dönüş değerleri içeriyorsa — bu stub'dır. Fake bakımı daha maliyetlidir ancak daha gerçekçi testler sağlar.
Fake mantığı üretim mantığıyla eşleşmediğinde. Örneğin, FakeUserRepository büyük/küçük harfe duyarlı arama kullanırken, üretim sürümü büyük/küçük harfe duyarsızdır. Test geçer ancak gerçekte bir hata vardır. Çözüm: fake mantığını ayrı ayrı test edin veya yalnızca basit mantığa (CRUD işlemleri) sahip arayüzler için fakes kullanın. Karmaşık mantık için gerçek bir veritabanıyla entegrasyon testleri yazın.
Bellek içi veritabanı bir fake türüdür. Room.inMemoryDatabaseBuilder(), üretim veritabanı gibi davranan bellek içi SQLite oluşturur. Bu tam teşekküllü bir fake'tir. Ancak fake, depo düzeyinde (SQL olmadan) ve ağ düzeyinde (FakeApiService) de olabilir. Bellek içi veritabanı, mantığın gerçeğe mümkün olduğunca yakın olduğu özel bir fake durumudur.
Evet, ancak dikkatli olun. Fake depo için (veri), Mock AnalyticsTracker için (olay doğrulama). Katmanlara göre ayırma: veri katmanı için fake, analitik/günlük katmanı için mock. Bir nesneyi aynı anda fake ve mock yapmayın — bu Tek Sorumluluk İlkesi'ni ihlal eder ve testi karıştırır.
Fake'i test edin üretim uygulamasıyla aynı testlerle. save, get, delete'i doğrulayan bir UserRepositoryTest'iniz varsa — iki kez çalıştırın: FakeUserRepository ve RealUserRepository ile. Bu, fake'in üretim sınıfının davranışını tekrarladığını garanti eder. Fake farklı davranmaya başlarsa — test her iki uygulamada da başarısız olur.
Özet
Anahtar teslim bir mobil uygulama geliştireceğiz
IT Sectr, 2017'den beri girişimler ve işletmeler için iOS ve Android uygulamaları oluşturmaktadır. Size danışmanlık yapacak ve en iyi çözümü önereceğiz.
Ayrıca okuyun