Fake — τι είναι, σκοπός και πώς να το χρησιμοποιήσετε στον έλεγχο

Συγγραφέας: IT Sectr Δημοσιεύτηκε: 2026-04-10 Χρόνος ανάγνωσης: 9 λεπ

Fake (φέικ) — μια λειτουργική απλοποιημένη υλοποίηση εξάρτησης που συμπεριφέρεται σαν πραγματικό στοιχείο, αλλά χρησιμοποιεί in-memory αποθήκευση ή άλλους ελαφρείς μηχανισμούς αντί για υποδομή παραγωγής. Σε αντίθεση με το stub, το fake περιέχει πραγματική επιχειρηματική λογική — ταξινόμηση, φιλτράρισμα, συγκέντρωση — απλά χωρίς εξωτερικές επιδράσεις. In-memory βάση δεδομένων αντί για Room ή HashMap αντί για SharedPreferences — κλασικά παραδείγματα. Περισσότερα στην ταξινόμηση test doubles του Martin Fowler.

Κύρια σημεία

  • Fake — απλοποιημένη λειτουργική υλοποίηση με πραγματική λογική, αλλά χωρίς εξωτερικές εξαρτήσεις
  • In-memory αποθήκευση — το fake-αποθετήριο αποθηκεύει δεδομένα σε HashMap, όχι σε βάση δεδομένων
  • Διαφορά από Stub — το stub επιστρέφει σταθερά δεδομένα, το fake περιέχει εκτελέσιμη λογική
  • Android — InMemoryUserRepository ως Fake για τον έλεγχο ViewModel και UseCase
  • iOS — FakeNetworkSession με URLProtocol και δοκιμαστικά δεδομένα αντί για πραγματικό διακομιστή

Τι είναι το Fake και γιατί χρειάζεται στον έλεγχο;

Fake — μια πλήρης αλλά ελαφριά υλοποίηση μιας διεπαφής, κατάλληλη για έλεγχο. Ο όρος εισήχθη από τον Gerard Meszaros (2007) στο βιβλίο «xUnit Test Patterns». Σε αντίθεση με το stub, το οποίο επιστρέφει αυστηρά προκαθορισμένες απαντήσεις, το fake περιέχει εκτελέσιμο κώδικα: μπορεί να ταξινομήσει μια λίστα, να φιλτράρει κατά συνθήκη, να μετρήσει εγγραφές. Η μόνη διαφορά από την υλοποίηση παραγωγής — το fake λειτουργεί με in-memory δεδομένα και δεν εκτελεί πραγματικές λειτουργίες I/O.

Κύριο πλεονέκτημα — ταχύτητα. Οι δοκιμές με fake εκτελούνται σε χιλιοστά του δευτερολέπτου, επειδή δεν υπάρχει πρόσβαση σε δίσκο, δίκτυο ή βάση δεδομένων. Το in-memory HashMap λειτουργεί 100-1000 φορές γρηγορότερα από το Room ή το CoreData. Ταυτόχρονα, το fake ελέγχει την πραγματική επιχειρηματική λογική: ταξινόμηση, φιλτράρισμα, συγκέντρωση — όλα όσα το stub δεν μπορεί να ελέγξει, επειδή το stub επιστρέφει μόνο ό,τι του είπαν. Το Fake παρέχει βεβαιότητα ότι ο κώδικας επεξεργάζεται σωστά τα δεδομένα, όχι απλώς λαμβάνει μια προκαθορισμένη απάντηση.

Πότε το Fake είναι προτιμότερο από το Stub

Το Fake είναι προτιμότερο από το Stub — αν το ελεγχόμενο στοιχείο εκτελεί πολλές λειτουργίες στα δεδομένα (εξήγαγε, φιλτράρισε, ταξινόμησε, αποθήκευσε), το stub θα απαιτήσει ρύθμιση κάθε κλήσης ξεχωριστά. Το Fake περιέχει τη λογική εσωτερικά — η δοκιμή απλώς καλεί μεθόδους και ελέγχει το αποτέλεσμα. Στην IT Sectr χρησιμοποιούμε fake για όλα τα αποθετήρια στις μοναδιαίες δοκιμές: το fake-αποθετήριο με HashMap καλύπτει το 90% των σεναρίων χωρίς ρύθμιση Mockito ή MockK.

Fake vs Stub vs Mock: πότε να επιλέξετε τι

Κριτήριο επιλογής — καθορίστε τι ελέγχει η δοκιμή: κατάσταση ή αλληλεπίδραση. Αν η δοκιμή ελέγχει την κατάσταση (αποτέλεσμα εργασίας) και χρησιμοποιεί λογική — χρειάζεται fake. Αν η δοκιμή χρειάζεται μόνο δεδομένα εισόδου χωρίς λογική — αρκεί stub. Αν η δοκιμή ελέγχει το γεγονός κλήσης μιας μεθόδου — χρειάζεται mock. Η ανάμειξη τύπων test doubles σε μία δοκιμή δυσκολεύει την κατανόηση και αυξάνει την ευθραυστότητα.

ΚριτήριοFakeStubMock
Ύπαρξη λογικήςΝαι (απλοποιημένη)ΌχιΌχι
ΤαχύτηταΥψηλήΜέγιστηΥψηλή
Έλεγχος συμπεριφοράςΈμμεσοςΌχιΝαι (verify)
ΣυντήρησηΜία κλάση ανά διεπαφήΡύθμιση ανά δοκιμήΡύθμιση ανά δοκιμή
ΡεαλισμόςΥψηλός (ο κώδικας λειτουργεί)Χαμηλός (σταθερά δεδομένα)Μέτριος
Κίνδυνος ψευδών συναγερμώνΧαμηλόςΜέτριοςΥψηλός (εύθραυστες δοκιμές)

Αντ-μοτίβο: Fake που δεν είναι fake — ένα συνηθισμένο λάθος όταν ο προγραμματιστής αποκαλεί fake ένα αντικείμενο που στην πραγματικότητα είναι stub ή mock. Αν το InMemoryUserRepository δεν περιέχει λογική (φιλτράρισμα, ταξινόμηση) — αυτό δεν είναι fake, αλλά stub με in-memory αποθήκευση. Το Fake διαφέρει από το stub ακριβώς στην ύπαρξη εκτελέσιμης λογικής. Αν το fake-αποθετήριο απλώς επιστρέφει ό,τι τοποθετήθηκε σε αυτό και δεν επεξεργάζεται δεδομένα — χρησιμοποιήστε mock ή stub.

Πρακτικός κανόνας επιλογής test double

Πρακτική σύσταση — ξεκινήστε με fake για κάθε αποθετήριο ή υπηρεσία. Αν το fake είναι πιο περίπλοκο από 50 γραμμές — χωρίστε το σε πολλές κλάσεις. Αν το fake δεν χρειάζεται καθόλου (η δοκιμή ελέγχει μόνο ένα σενάριο με σταθερά δεδομένα) — χρησιμοποιήστε stub. Αν η δοκιμή ελέγχει αν μια μέθοδος κλήθηκε με συγκεκριμένες παραμέτρους — χρησιμοποιήστε mock. Μην βελτιστοποιείτε την επιλογή εκ των προτέρων: γράψτε fake, και αν αποδειχθεί περιττό, αντικαταστήστε το με stub στη συγκεκριμένη δοκιμή.

Δημιουργία Fake-αντικειμένων σε Android για Room και Retrofit

Fake-αποθετήριο για Room — τυπικό παράδειγμα fake σε Android. Η υλοποίηση παραγωγής UserRepository χρησιμοποιεί Room DAO με ερωτήματα SQLite. Η έκδοση fake αποθηκεύει δεδομένα σε MutableList ή HashMap και υλοποιεί τις ίδιες μεθόδους: getUser(id), saveUser(user), deleteUser(id). Το Fake περιέχει λογική αναζήτησης, φιλτραρίσματος και ταξινόμησης — ίδια με το αποθετήριο παραγωγής, αλλά χωρίς SQL. Αυτό επιτρέπει τον έλεγχο ViewModel και UseCase χωρίς ρύθμιση της βάσης Room.

kotlin
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)
        }
    }
}

Fake για Retrofit API — αντί για MockWebServer (που είναι stub, όχι fake) μπορεί να δημιουργηθεί μια υλοποίηση ApiService που επιστρέφει δεδομένα από μια in-memory συλλογή. Διαφορά: το MockWebServer υποκλέπτει HTTP και επιστρέφει JSON, ενώ το fake-ApiService λειτουργεί σε επίπεδο διεπαφής Kotlin χωρίς σειριοποίηση. Το fake είναι ταχύτερο (χωρίς ανάλυση JSON) και απλούστερο στον εντοπισμό σφαλμάτων (λειτουργεί στην ίδια διεργασία, με τύπους). Κατάλληλο για δοκιμές όπου η σημασιολογία HTTP (κωδικοί κατάστασης, κεφαλίδες) δεν είναι σημαντική.

FakeSharedPreferences για γρήγορες δοκιμές

— ένα ακόμη συνηθισμένο σενάριο. Οι SharedPreferences παραγωγής γράφουν στο δίσκο μέσω commit/apply. Η έκδοση fake αποθηκεύει ζεύγη κλειδιού-τιμής σε HashMap και επιστρέφει άμεσα δεδομένα. Υποστηρίζει τις ίδιες μεθόδους: getString, putString, getInt, putInt, clear. Για το Jetpack DataStore το ανάλογο είναι FakeDataStore με in-memory αποθήκευση. Τέτοια fake επιταχύνουν τις δοκιμές δεκάδες φορές, επειδή δεν υπάρχουν λειτουργίες εγγραφής στο δίσκο.

Υλοποιήσεις Fake σε iOS με in-memory αποθηκεύσεις

Fake σε Swift — χτίζεται μέσω πρωτοκόλλων. Η κλάση παραγωγής υλοποιεί το πρωτόκολλο με πραγματική λογική (CoreData, URLSession). Η δομή fake υλοποιεί το ίδιο πρωτόκολλο με in-memory αποθήκευση και απλοποιημένη λογική. Η Swift είναι γλώσσα με σημασιολογία τιμής, επομένως οι δομές fake είναι αμετάβλητες και ασφαλείς σε δοκιμές πολλαπλών νημάτων. Αυτό δίνει πλεονέκτημα έναντι των αναλόγων Android: η πρόσβαση σε in-memory δεδομένα δεν χρειάζεται συγχρονισμό.

swift
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")
    }
}

Fake για CoreData — σε έργα iOS μπορεί να δημιουργηθεί ένα in-memory NSPersistentContainer ορίζοντας description.type = NSInMemoryStoreType. Αυτή είναι μια πλήρης στοίβα CoreData που λειτουργεί στη μνήμη. Ένα τέτοιο fake επιτρέπει τον έλεγχο NSFetchRequest, κατηγορημάτων και ταξινομήσεων χωρίς δημιουργία αρχείου SQLite. Ταχύτητα: οι δοκιμές σε in-memory CoreData εκτελούνται 5-10 φορές γρηγορότερα από το ανάλογο σε δίσκο. Μειονέκτημα: το NSManagedObjectModel πρέπει να ρυθμίζεται κάθε φορά.

FakeURLProtocol — μια υποκλάση του URLProtocol για υποκλοπή αιτημάτων δικτύου σε iOS. Καταχωρείται μέσω URLProtocol.registerClass(fakeProtocol). Εσωτερικά περιέχει ένα in-memory λεξικό URL -> Data και επιστρέφει δεδομένα χωρίς πραγματικό αίτημα. Διαφορά από stub: το FakeURLProtocol μπορεί να ελέγξει το σώμα του αιτήματος, τις κεφαλίδες και να επιστρέψει διαφορετικές απαντήσεις ανάλογα με τα δεδομένα εισόδου. Αυτό είναι fake επειδή περιέχει λογική δρομολόγησης αιτημάτων.

Μοτίβα χρήσης Fake σε κινητά έργα

Fake ως Test Fixture — μεταφέρετε τις κλάσεις fake σε ένα κοινό άρθρωμα δοκιμών (androidTest/sharedTest ή TestSupport). Όλες οι δοκιμές στο έργο χρησιμοποιούν το ίδιο InMemoryUserRepository. Αυτό εξαλείφει την αντιγραφή της ρύθμισης αντικειμένων mock σε κάθε δοκιμή και εγγυάται ομοιόμορφη συμπεριφορά. Η αλλαγή της λογικής fake ενημερώνει όλες τις δοκιμές ταυτόχρονα. Στην IT Sectr αποθηκεύουμε τις κλάσεις fake στο sharedTest/java/com/itSectr/fake/ και τις συνδέουμε μέσω implementation project(:sharedTest).

Fake με προκαθορισμένα δεδομένα — συχνά οι δοκιμές χρειάζονται ένα αποθετήριο που ήδη περιέχει κάποιες εγγραφές. Λύση: μέθοδος εργοστασίου fakeWithData(vararg items) ή ενσωματωμένη μέθοδος addDefaultData(). Το εργοστάσιο δημιουργεί fake, το γεμίζει με τυπικά δεδομένα και επιστρέφει ένα έτοιμο προς χρήση αντικείμενο. Αυτό μειώνει το boilerplate στις δοκιμές: αντί να ρυθμίζετε κλήσεις mock, η δοκιμή απλώς καλεί FakeUserRepository.withUsers(alice, bob).

Fake με καταμέτρηση κλήσεων — μερικές φορές χρειάζεται να ελέγξετε όχι μόνο την κατάσταση, αλλά και τον αριθμό των κλήσεων. Το Fake μπορεί να περιέχει μετρητές: saveCallCount, getUserCallCount. Η δοκιμή ελέγχει τον μετρητή μετά την εκτέλεση. Αυτός είναι ένας συμβιβασμός μεταξύ καθαρού fake (έλεγχος κατάστασης) και mock (έλεγχος αλληλεπίδρασης). Οι μετρητές δεν ελέγχουν ορίσματα και σειρά κλήσεων — μόνο τον αριθμό. Για έλεγχο ορισμάτων χρησιμοποιήστε mock.

Fake με Callback — για δοκιμή ασύγχρονων σεναρίων, το fake μπορεί να δέχεται callback σε κάθε κλήση: beforeGetUser, afterSaveUser. Αυτό επιτρέπει την προσομοίωση καθυστερήσεων, σφαλμάτων ή τον έλεγχο ενδιάμεσων καταστάσεων. Αυτή η προσέγγιση είναι χρήσιμη για τη δοκιμή καταστάσεων φόρτωσης UI: το fake κάνει παύση 100 ms και η δοκιμή ελέγχει αν η οθόνη εμφανίζει φορτωτή. Στην παραγωγή το callback δεν υπάρχει — είναι καθαρά λειτουργία δοκιμής.

Συχνές ερωτήσεις

Σε τι διαφέρει το Fake από το Stub;

Fake περιέχει λειτουργική λογική — φιλτράρει, ταξινομεί, μετρά. Το Stub επιστρέφει μόνο προκαθορισμένες απαντήσεις χωρίς λογική. Αν το αντικείμενο έχει διακλαδώσεις (if/else, when) — είναι fake. Αν περιέχει μόνο return values — είναι stub. Το fake είναι ακριβότερο στη συντήρηση, αλλά δίνει πιο ρεαλιστικές δοκιμές.

Πότε το fake μπορεί να είναι επιβλαβές;

Όταν η λογική fake δεν συμπίπτει με τη λογική παραγωγής. Για παράδειγμα, το FakeUserRepository χρησιμοποιεί case-sensitive αναζήτηση, ενώ η παραγωγή χρησιμοποιεί case-insensitive. Η δοκιμή περνά, αλλά στην πραγματικότητα υπάρχει σφάλμα. Λύση: δοκιμάστε τη λογική fake ξεχωριστά ή χρησιμοποιήστε fakes μόνο για διεπαφές με απλή λογική (λειτουργίες CRUD). Για σύνθετη λογική γράψτε δοκιμές ολοκλήρωσης με πραγματική βάση δεδομένων.

Είναι το Fake το ίδιο με το in-memory database;

In-memory database — μία από τις παραλλαγές του fake. Το Room.inMemoryDatabaseBuilder() δημιουργεί ένα in-memory SQLite που συμπεριφέρεται σαν βάση δεδομένων παραγωγής. Αυτό είναι ένα πλήρες fake. Αλλά το fake μπορεί να είναι και σε επίπεδο αποθετηρίου (χωρίς SQL) και σε επίπεδο δικτύου (FakeApiService). Η in-memory βάση δεδομένων είναι μια ειδική περίπτωση fake όπου η λογική είναι όσο το δυνατόν πιο κοντά στην πραγματική.

Μπορούν να συνδυαστούν Fake και Mock σε μία δοκιμή;

Ναι, αλλά με προσοχή. Fake για το αποθετήριο (δεδομένα), Mock για το AnalyticsTracker (επαλήθευση συμβάντων). Διαχωρισμός ανά επίπεδο: fake για το επίπεδο δεδομένων, mock για το επίπεδο ανάλυσης/καταγραφής. Μην κάνετε ένα αντικείμενο ταυτόχρονα fake και mock — αυτό παραβιάζει την Αρχή της Μοναδικής Ευθύνης και μπερδεύει τη δοκιμή.

Πώς δοκιμάζουμε το ίδιο το Fake;

Δοκιμάστε το fake με τις ίδιες δοκιμές όπως και την υλοποίηση παραγωγής. Αν έχετε UserRepositoryTest που ελέγχει save, get, delete — εκτελέστε το δύο φορές: με FakeUserRepository και με RealUserRepository. Αυτό εγγυάται ότι το fake επαναλαμβάνει τη συμπεριφορά της κλάσης παραγωγής. Αν το fake αρχίσει να συμπεριφέρεται διαφορετικά — η δοκιμή θα αποτύχει και στις δύο υλοποιήσεις.

Σύνοψη

  • Fake — λειτουργική απλοποιημένη υλοποίηση εξάρτησης με πραγματική επιχειρηματική λογική και in-memory αποθήκευση
  • Διαφορά από Stub — το fake περιέχει λογική (φιλτράρισμα, ταξινόμηση), το stub μόνο επιστρέφει δεδομένα
  • Ταχύτητα — το fake λειτουργεί 100-1000 φορές γρηγορότερα από την υλοποίηση παραγωγής χωρίς λειτουργίες I/O
  • Android — InMemoryUserRepository, FakeDataStore, in-memory Room μέσω Room.inMemoryDatabaseBuilder
  • iOS — fake βασισμένο σε πρωτόκολλο, in-memory CoreData, FakeURLProtocol για υποκλοπή HTTP
  • Βέλτιστη πρακτική — μεταφέρετε το fake σε κοινό άρθρωμα δοκιμών και χρησιμοποιήστε σε όλες τις δοκιμές του έργου
  • Δοκιμάστε το fake — εκτελέστε τις ίδιες δοκιμές στο fake και στην υλοποίηση παραγωγής για έλεγχο συνέπειας

Θα αναπτύξουμε μια εφαρμογή για κινητά έτοιμη για χρήση

Η IT Sectr δημιουργεί εφαρμογές iOS και Android για νεοφυείς επιχειρήσεις και επιχειρήσεις από το 2017. Θα σας συμβουλεύσουμε και θα προτείνουμε την καλύτερη λύση.

Συζήτηση έργου

Διαβάστε επίσης