Mockito — τι είναι, βασικές έννοιες και αρχή λειτουργίας

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

Το Mockito είναι ένα framework ανοιχτού κώδικα για τη δημιουργία mock-αντικειμένων σε unit tests Java και Kotlin, το οποίο επιτρέπει την απομόνωση του υπό δοκιμή κώδικα από εξωτερικές εξαρτήσεις. Με τη βοήθειά του, ο προγραμματιστής αντικαθιστά πραγματικά repositories, API clients και βάσεις δεδομένων με ελεγχόμενα υποκατάστατα με καθορισμένη συμπεριφορά. Σύμφωνα με τα δεδομένα του Mockito.org, η βιβλιοθήκη χρησιμοποιείται σε περισσότερο από 60% των Java έργων που εφαρμόζουν unit testing.

Κύρια σημεία

  • Mockito — βιβλιοθήκη για δημιουργία mock-αντικειμένων που αντικαθιστούν πραγματικές εξαρτήσεις στα tests.
  • Mock — ένα υποκατάστατο αντικείμενο που μιμείται τη συμπεριφορά ενός πραγματικού component.
  • Stubbing — ρύθμιση της επιστρεφόμενης τιμής κατά την κλήση της μεθόδου του mock.
  • Verify — έλεγχος ότι η μέθοδος κλήθηκε με συγκεκριμένα ορίσματα.
  • @InjectMocks — αυτόματη έγχυση mock-εξαρτήσεων στο υπό δοκιμή αντικείμενο.

Τι είναι το Mockito;

Το Mockito είναι μια βιβλιοθήκη ανοιχτού κώδικα για τη δημιουργία mock-αντικειμένων (υποκατάστατων) σε unit tests σε Java, Kotlin και άλλες γλώσσες JVM. Σε αντίθεση με το JUnit, που είναι υπεύθυνο για την εκτέλεση των tests, το Mockito λύνει το πρόβλημα της απομόνωσης — αντικαθιστά τις πραγματικές εξαρτήσεις της υπό δοκιμή κλάσης με προβλέψιμα αντικείμενα.

Χωρίς mocks, η δοκιμή μιας μεθόδου που έχει πρόσβαση σε βάση δεδομένων ή εξωτερικό API απαιτεί ρύθμιση πραγματικού περιβάλλοντος — ανάπτυξη βάσης δεδομένων, εκκίνηση διακομιστή. Το Mockito αντικαθιστά αυτές τις εξαρτήσεις με αντικείμενα σταθερής συμπεριφοράς: η μέθοδος repository.findById(1) επιστρέφει πάντα ένα συγκεκριμένο αντικείμενο User, χωρίς να προσπελαύνει τη βάση δεδομένων.

Η αρχιτεκτονική του Mockito βασίζεται στο μοτίβο Proxy (για interfaces και κλάσεις). Η βιβλιοθήκη δημιουργεί μια υποκλάση ή proxy για τον καθορισμένο τύπο και παρεμποδίζει όλες τις κλήσεις μεθόδων, επιστρέφοντας προεπιλεγμένες τιμές ή τιμές που ορίζονται μέσω του when().thenReturn().

Πώς λειτουργεί το Mockito

Η αρχή λειτουργίας του Mockito βασίζεται σε τρεις βασικές λειτουργίες: δημιουργία mock, ρύθμιση συμπεριφοράς (stubbing) και επαλήθευση κλήσεων (verification). Κάθε λειτουργία χρησιμοποιεί στατικές μεθόδους από την κλάση org.mockito.Mockito — την πιο φορτωμένη κλάση στο οικοσύστημα Java σύμφωνα με στατιστικά του Maven Central. Όλες οι κλήσεις μεθόδων του mock καταγράφονται στη μνήμη, επιτρέποντας τον μετέπειτα έλεγχό τους μέσω verify.

Τρία βήματα του test με Mockito

Ένα τυπικό test με Mockito αποτελείται από τρεις φάσεις: Arrange — δημιουργία mocks και ρύθμιση stubs μέσω when().thenReturn(), Act — κλήση της υπό δοκιμή μεθόδου, Assert — έλεγχος αποτελέσματος μέσω assertEquals και verify(mock). Αυτή η προσέγγιση ονομάζεται AAA (Arrange-Act-Assert).

Βασικό παράδειγμα με mock repository

Ας εξετάσουμε ένα απλό test όπου το Mockito αντικαθιστά το repository χρηστών. Η μέθοδος when().thenReturn() ρυθμίζει το mock έτσι ώστε η κλήση findById να επιστρέφει ένα προετοιμασμένο αντικείμενο User.

java
// Δημιουργούμε mock του repository
UserRepository mockRepo = mock(UserRepository.class);

// Ρυθμίζουμε συμπεριφορά: στο findById(1) επέστρεψε τον χρήστη
when(mockRepo.findById(1)).thenReturn(new User("Alice"));

// Ελέγχουμε ότι η μέθοδος κλήθηκε πραγματικά
User result = mockRepo.findById(1);
assertEquals("Alice", result.getName());
verify(mockRepo).findById(1);

Δημιουργία mock-αντικειμένων

Το Mockito παρέχει δύο τρόπους δημιουργίας mocks: τη στατική μέθοδο mock(Class) και το annotation @Mock με αρχικοποίηση μέσω MockitoAnnotations.openMocks(). Ο πρώτος τρόπος είναι συμπαγής για ένα-δύο mocks, ο δεύτερος είναι βολικός όταν υπάρχουν πολλές εξαρτήσεις — τα annotations μειώνουν τον boilerplate κώδικα.

Μέσω της στατικής μεθόδου mock()

Η μέθοδος mock() δέχεται μια κλάση και επιστρέφει ένα υποκατάστατο αντικείμενο που μπορεί να ρυθμιστεί μέσω when().thenReturn(). Όλες οι μη ρυθμισμένες μέθοδοι επιστρέφουν προεπιλεγμένες τιμές: 0 για αριθμούς, false για boolean, null για αντικείμενα.

java
ApiClient apiClient = mock(ApiClient.class);
Database database = mock(Database.class);

Μέσω του annotation @Mock με JUnit 5

Το annotation @Mock σε συνδυασμό με @ExtendWith(MockitoExtension.class) δημιουργεί αυτόματα mocks για όλα τα πεδία της κλάσης test. Η επέκταση MockitoExtension είναι υπεύθυνη για την αρχικοποίηση πριν από κάθε test.

java
@ExtendWith(MockitoExtension.class)
class UserServiceTest {

    @Mock
    private UserRepository userRepository;

    @InjectMocks
    private UserService userService;

    @Test
    void getUserShouldReturnUserFromRepo() {
        when(userRepository.findById(1)).thenReturn(new User("Alice"));
        User result = userService.getUser(1);
        assertEquals("Alice", result.getName());
    }
}

Stubbing: ρύθμιση συμπεριφοράς mock

Stubbing — η διαδικασία καθορισμού του τι πρέπει να επιστρέψει η μέθοδος mock όταν καλείται με συγκεκριμένα ορίσματα. Βασική σύνταξη: when(mock.method(args)).thenReturn(value). Για διαφορετικά σενάρια, το Mockito προσφέρει αρκετές παραλλαγές μεθόδων then.

ΜέθοδοςΣκοπός
thenReturn(value)Επιστρέφει πάντα την καθορισμένη τιμή
thenThrow(exception)Πετάει exception κατά την κλήση
thenAnswer(answer)Υπολογίζει δυναμικά την επιστρεφόμενη τιμή
thenCallRealMethod()Καλεί την πραγματική μέθοδο (μερικό mock)

Δυναμική απάντηση μέσω thenAnswer

Όταν η επιστρεφόμενη τιμή εξαρτάται από τα ορίσματα κλήσης, χρησιμοποιείται το thenAnswer με lambda. Αυτό είναι χρήσιμο για προσομοίωση εργασίας με πραγματικά δεδομένα — για παράδειγμα, δημιουργία ID βάσει του μεταβιβαζόμενου αντικειμένου.

java
when(repository.save(any())).thenAnswer(invocation -> {
    User user = invocation.getArgument(0);
    user.setId(42);
    return user;
});

Verify: έλεγχος αλληλεπιδράσεων με το mock

Το Verify είναι μια μοναδική δυνατότητα του Mockito που δεν παρέχουν οι παλαιότερες βιβλιοθήκες mock-αντικειμένων (EasyMock, jMock).

Το Verify κάνει τα tests πιο αξιόπιστα, καθώς ελέγχει όχι μόνο την επιστρεφόμενη τιμή, αλλά και τις παρενέργειες — κλήσεις μεθόδων που δεν επιστρέφουν αποτέλεσμα (void μέθοδοι). Η μέθοδος verify(mock).methodName(args) ελέγχει αν μια συγκεκριμένη μέθοδος του mock κλήθηκε με τα καθορισμένα ορίσματα. Αυτό επιτρέπει τη δοκιμή όχι μόνο του αποτελέσματος, αλλά και της διαδικασίας — του γεγονότος πρόσβασης στην εξάρτηση.

Έλεγχος αριθμού κλήσεων

Από προεπιλογή, το verify ελέγχει ότι η μέθοδος κλήθηκε ακριβώς μία φορά. Αν χρειάζεται διαφορετικός αριθμός — χρησιμοποιούνται τα times(n), atLeast(n), never() και άλλοι τροποποιητές από την κλάση Mockito.

java
// Έλεγχος αριθμού κλήσεων
verify(repository, times(3)).save(any());
verify(repository, never()).delete(any());
verify(repository, atLeastOnce()).findById(1);

// Έλεγχος σειράς κλήσεων
InOrder inOrder = inOrder(repository);
inOrder.verify(repository).save(any());
inOrder.verify(repository).flush();

ArgumentCaptor για καταγραφή ορισμάτων

Όταν πρέπει να ελεγχθεί με ποιο ακριβώς αντικείμενο κλήθηκε η μέθοδος, χρησιμοποιείται το ArgumentCaptor. Αυτό καταγράφει την τιμή του ορίσματος κατά την κλήση και επιτρέπει τον ξεχωριστό έλεγχο των πεδίων του. Το ArgumentCaptor είναι ιδιαίτερα χρήσιμο όταν ο υπό δοκιμή κώδικας δημιουργεί ένα αντικείμενο εσωτερικά και το μεταβιβάζει στην εξάρτηση — δεν μπορείτε να ελέγξετε αυτό το αντικείμενο με άλλον τρόπο.

java
ArgumentCaptor<User> captor = ArgumentCaptor.forClass(User.class);
verify(repository).save(captor.capture());
assertEquals("Alice", captor.getValue().getName());

Annotations @Mock και @InjectMocks

@Mock και @InjectMocks — δύο βασικά annotations του Mockito που μειώνουν σημαντικά τον boilerplate κώδικα. Το @Mock δημιουργεί ένα mock για ένα πεδίο, και το @InjectMasks εισάγει όλα τα mocks από την κλάση test στο υπό δοκιμή αντικείμενο μέσω κατασκευαστή, setter ή πεδίου.

Ο μηχανισμός @InjectMocks προσπαθεί να εισαγάγει εξαρτήσεις με την ακόλουθη σειρά: κατασκευαστής με τον μεγαλύτερο αριθμό ορισμάτων, setter ανά τύπο, ιδιωτικό πεδίο. Αν καμία μέθοδος δεν λειτουργήσει — το αντικείμενο παραμένει με null εξαρτήσεις και το test αποτυγχάνει με NullPointerException.

Κανόνες χρήσης του @InjectMocks

Είναι σημαντικό να κατανοήσετε: το @InjectMocks δεν αναλύει τους τύπους πεδίων — εισάγει οποιοδήποτε mock είναι συμβατό με τον τύπο. Αν η κλάση έχει δύο πεδία του ίδιου τύπου — το Mockito μπορεί να εισαγάγει λάθος mock. Σε τέτοιες περιπτώσεις, συνιστάται η χρήση ρητού κατασκευαστή με μεταβίβαση των mocks.

Mockito σε Android έργα

Στην ανάπτυξη Android, το Mockito χρησιμοποιείται μαζί με το JUnit για τη δοκιμή ViewModel, Repository και UseCase. Δεδομένου ότι αυτές οι κλάσεις εκτελούνται σε JVM χωρίς περιβάλλον Android, το Mockito αντικαθιστά τις εξαρτήσεις τους — Room DAO, Retrofit API, SharedPreferences — με stubs προβλέψιμης συμπεριφοράς.

Ρύθμιση Gradle για Mockito

Για να προσθέσετε το Mockito σε ένα Android έργο, αρκεί να προσθέσετε την εξάρτηση mockito-core ή mockito-inline (η τελευταία υποστηρίζει mocking τελικών κλάσεων και στατικών μεθόδων). Η έκδοση 5.12.0 (2024) περιλαμβάνει υποστήριξη για Java 21 και βελτιωμένη ενσωμάτωση με JUnit 5.

kotlin
// build.gradle.kts (module)
dependencies {
    testImplementation("org.mockito:mockito-core:5.12.0")
    testImplementation("org.mockito:mockito-junit-jupiter:5.12.0")
}

Mockito και PowerMock: παρωχημένη πρακτική

Παλαιότερα, για το mocking στατικών μεθόδων και κατασκευαστών απαιτείτο το PowerMock — μια επέκταση που λειτουργούσε μέσω bytecode instrumentation. Από το Mockito 5.x με mockito-inline, αυτή η λειτουργικότητα είναι ενσωματωμένη απευθείας: το mockStatic(ClassName.class) επιτρέπει το mocking στατικών μεθόδων χωρίς πρόσθετες βιβλιοθήκες.

Δοκιμή ViewModel με Mockito

Τυπικό σενάριο: το ViewModel καλεί μια μέθοδο του repository και μετασχηματίζει το αποτέλεσμα σε κατάσταση UI. Το Mockito αντικαθιστά το repository και το test ελέγχει ότι το ViewModel επεξεργάζεται σωστά την επιτυχημένη απόκριση και το σφάλμα. Κατά τη χρήση της Clean Architecture, δημιουργούνται mocks για κάθε επίπεδο: DataSource, Repository και UseCase — αυτό επιτρέπει τη δοκιμή κάθε επιπέδου απομονωμένα.

  • success case — when(repo.getData()).thenReturn(Result.success(data)) → ελέγχουμε state = Success(data).
  • error case — when(repo.getData()).thenReturn(Result.error(exception)) → ελέγχουμε state = Error(message).
  • loading state — verify ότι το ViewModel έθεσε isLoading = true πριν από την κλήση του repository.

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

Σε τι διαφέρει το Mockito από το MockK;

Mockito είναι μια βιβλιοθήκη για Java και Kotlin που χρησιμοποιεί proxy και reflection. Το MockK είναι μια Kotlin-first βιβλιοθήκη με υποστήριξη για coroutines, extension functions και τελικές κλάσεις χωρίς πρόσθετη ρύθμιση.

Πώς δημιουργείτε mock για τελική κλάση στο Mockito;

Από το Mockito 2.1, το mocking τελικών κλάσεων υποστηρίζεται μέσω opt-in. Στην έκδοση 5.x (mockito-inline) αυτό είναι ενεργοποιημένο από προεπιλογή. Αρκεί να προσθέσετε την εξάρτηση mockito-inline και να χρησιμοποιήσετε την τυπική μέθοδο mock().

Τι είναι το Spy στο Mockito;

Spy είναι ένα μερικό mock που από προεπιλογή καλεί πραγματικές μεθόδους, αλλά επιτρέπει την παράκαμψη ορισμένων από αυτές μέσω when().thenReturn(). Το Spy είναι χρήσιμο για δοκιμή παλαιού κώδικα όταν δεν μπορεί να ξαναγραφεί ολόκληρη η κλάση.

Ποια είναι η διαφορά μεταξύ thenReturn και thenAnswer;

thenReturn επιστρέφει πάντα την ίδια τιμή, ανεξάρτητα από τα ορίσματα. thenAnswer υπολογίζει την επιστρεφόμενη τιμή με βάση την κλήση — ορίσματα, το ίδιο το mock, κατάσταση. Για δυναμικές απαντήσεις, χρησιμοποιείτε πάντα το thenAnswer.

Γιατί είναι σημαντικό το verify στα tests με mocks;

Verify ελέγχει όχι μόνο το αποτέλεσμα, αλλά και τη διαδικασία — το γεγονός πρόσβασης στην εξάρτηση. Αυτό είναι κρίσιμο για υπηρεσίες που πρέπει να αποθηκεύουν δεδομένα ή να στέλνουν ειδοποιήσεις. Χωρίς verify, το test δεν θα ανιχνεύσει ότι η μέθοδος δεν κάλεσε save() ή send().

Σύνοψη

  • Mockito — βιβλιοθήκη δημιουργίας mock-αντικειμένων, de facto πρότυπο για mocking σε Java και Kotlin.
  • Mocks δημιουργούνται μέσω mock(Class) ή του annotation @Mock με MockitoExtension.
  • Stubbing μέσω when().thenReturn() καθορίζει τη συμπεριφορά των μεθόδων mock.
  • Verify ελέγχει το γεγονός και τον αριθμό κλήσεων των μεθόδων mock με καθορισμένα ορίσματα.
  • @InjectMocks εισάγει αυτόματα τα mocks στο υπό δοκιμή αντικείμενο.
  • Ενσωμάτωση Android — το Mockito χρησιμοποιείται για δοκιμή ViewModel, Repository και UseCase.
  • ArgumentCaptor καταγράφει ορίσματα κλήσεων για λεπτομερή έλεγχο πεδίων αντικειμένου.

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

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

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

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