Mockito — Java və Kotlin-də modul testlərində mock-obyektlər yaratmaq üçün açıq mənbəli bir freymvorkdur. Bu, test edilən kodu xarici asılılıqlardan təcrid etməyə imkan verir. Onun köməyi ilə tərtibatçı real repozitoriləri, API müştərilərini və verilənlər bazalarını idarə olunan saxta obyektlərlə əvəz edir. Mockito.org məlumatlarına görə, kitabxana modul testləri tətbiq edən Java layihələrinin 60%-dən çoxunda istifadə olunur.
Əsas məqamlar
Mockito — Java, Kotlin və digər JVM dillərində modul testlərində mock-obyektlər (saxta obyektlər) yaratmaq üçün açıq mənbəli kitabxana. JUnit testlərin işə salınmasına cavabdeh olduğu halda, Mockito təcridetmə problemini həll edir — test edilən sinfin real asılılıqlarını proqnozlaşdırıla bilən obyektlərlə əvəz edir.
Mocklar olmadan verilənlər bazasına və ya xarici API-yə müraciət edən metodu test etmək real mühitin qurulmasını tələb edir — DB-nin yerləşdirilməsi, serverin işə salınması. Mockito bu asılılıqları sabit davranışlı obyektlərlə əvəz edir: repository.findById(1) metodu verilənlər bazasına müraciət etmədən həmişə müəyyən User obyektini qaytarır.
Mockito arxitekturası Proxy nümunəsinə əsaslanır (interfeyslər və siniflər üçün). Kitabxana müəyyən tip üçün alt sinif və ya proxy yaradır və bütün metod çağırışlarını ələ keçirərək standart və ya when().thenReturn() ilə təyin edilmiş dəyərləri qaytarır.
İş prinsipi Mockito üç əsas əməliyyata əsaslanır: mock yaratma, davranışın konfiqurasiyası (stubbing) və çağırışların yoxlanması (verification). Hər bir əməliyyat Maven Central statistikasına görə Java ekosistemində ən çox yüklənən sinif olan org.mockito.Mockito sinfindən statik metodlardan istifadə edir. Mock-un bütün metod çağırışları yaddaşda qeydə alınır ki, bu da onları sonradan verify vasitəsilə yoxlamağa imkan verir.
Mockito ilə tipik test üç fazadan ibarətdir: Arrange — mockların yaradılması və stub-ların when().thenReturn() ilə konfiqurasiyası, Act — test edilən metodun çağırılması, Assert — nəticənin assertEquals və verify(mock) ilə yoxlanması. Bu yanaşma AAA (Arrange-Act-Assert) adlanır.
Mockito-nun istifadəçi repozitorisini əvəz etdiyi sadə bir testə baxaq. when().thenReturn() metodu mock-u elə konfiqurasiya edir ki, findById çağırışı əvvəlcədən hazırlanmış User obyektini qaytarsın.
// Repozitoriya mock-u yaradırıq
UserRepository mockRepo = mock(UserRepository.class);
// Davranışı konfiqurasiya edirik: findById(1) çağırıldıqda istifadəçini qaytar
when(mockRepo.findById(1)).thenReturn(new User("Alice"));
// Metodun həqiqətən çağırıldığını yoxlayırıq
User result = mockRepo.findById(1);
assertEquals("Alice", result.getName());
verify(mockRepo).findById(1);
Mockito mock yaratmağın iki yolunu təqdim edir: statik mock(Class) metodu və MockitoAnnotations.openMocks() ilə işə salınan @Mock annotasiyası. Birinci üsul bir-iki mock üçün yığcamdır, ikincisi isə çoxlu asılılıq olduqda rahatdır — annotasiyalar boilerplate kodu azaldır.
mock() metodu sinfi qəbul edir və when().thenReturn() ilə konfiqurasiya edilə bilən saxta obyekt qaytarır. Konfiqurasiya edilməmiş metodlar standart dəyərlər qaytarır: ədədlər üçün 0, boolean üçün false, obyektlər üçün null.
ApiClient apiClient = mock(ApiClient.class);
Database database = mock(Database.class);
@Mock annotasiyası @ExtendWith(MockitoExtension.class) ilə birlikdə test sinfinin bütün sahələri üçün avtomatik mocklar yaradır. MockitoExtension genişlənməsi hər testdən əvvəl işə salınmaya cavabdehdir.
@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 — müəyyən arqumentlərlə çağırıldıqda mock metodunun nə qaytarmalı olduğunu təyin etmə prosesi. Əsas sintaksis: when(mock.method(args)).thenReturn(value). Müxtəlif ssenarilər üçün Mockito bir neçə then-metodu variantı təklif edir.
| Metod | Məqsəd |
|---|---|
| thenReturn(value) | Həmişə göstərilən dəyəri qaytarır |
| thenThrow(exception) | Çağırış zamanı istisna atır |
| thenAnswer(answer) | Qaytarılan dəyəri dinamik hesablayır |
| thenCallRealMethod() | Həqiqi metodu çağırır (qismən mock) |
Qaytarılan dəyər çağırış arqumentlərindən asılı olduqda, lambda ilə thenAnswer istifadə olunur. Bu, real verilənlərlə işin təqlid edilməsi üçün faydalıdır — məsələn, ötürülən obyekt əsasında ID generasiyası.
when(repository.save(any())).thenAnswer(invocation -> {
User user = invocation.getArgument(0);
user.setId(42);
return user;
});
Verify — Mockito-nun unikal imkanıdır, onu köhnə mock-obyekt kitabxanaları (EasyMock, jMock) təmin etmir.
Verify testləri daha etibarlı edir, çünki yalnız qaytarılan dəyəri deyil, həm də yan təsirləri — nəticə qaytarmayan metod çağırışlarını (void metodları) yoxlayır. verify(mock).methodName(args) metodu müəyyən mock metodunun göstərilən arqumentlərlə çağırılıb-çağırılmadığını yoxlayır. Bu, təkcə nəticəni deyil, həm də prosesi — asılılığa müraciət faktını test etməyə imkan verir.
Standart olaraq verify metodun dəqiq bir dəfə çağırıldığını yoxlayır. Fərqli say lazım olduqda — times(n), atLeast(n), never() və Mockito sinfindən digər modifikatorlardan istifadə olunur.
// Çağırış sayının yoxlanması
verify(repository, times(3)).save(any());
verify(repository, never()).delete(any());
verify(repository, atLeastOnce()).findById(1);
// Çağırış ardıcıllığının yoxlanması
InOrder inOrder = inOrder(repository);
inOrder.verify(repository).save(any());
inOrder.verify(repository).flush();
Metodun hansı obyektlə çağırıldığını yoxlamaq lazım olduqda ArgumentCaptor istifadə olunur. O, çağırış zamanı arqumentin dəyərini tutur və onun sahələrini ayrıca yoxlamağa imkan verir. ArgumentCaptor xüsusilə test edilən kodun daxildə obyekt yaradıb onu asılılığa ötürdüyü hallarda faydalıdır — bu obyekti başqa cür yoxlamaq mümkün deyil.
ArgumentCaptor<User> captor = ArgumentCaptor.forClass(User.class);
verify(repository).save(captor.capture());
assertEquals("Alice", captor.getValue().getName());
@Mock və @InjectMocks — Mockito-nun iki əsas annotasiyasıdır ki, onlar boilerplate kodu əhəmiyyətli dərəcədə azaldır. @Mock sahə üçün mock yaradır, @InjectMocks isə test sinfindən bütün mockları test edilən obyektə konstruktor, setter və ya sahə vasitəsilə yerləşdirir.
@InjectMocks mexanizmi asılılıqları aşağıdakı ardıcıllıqla yerləşdirməyə çalışır: ən çox arqumentə malik konstruktor, tipə görə setter, özəl sahə. Heç bir üsul işləməzsə — obyekt null asılılıqları ilə qalır və test NullPointerException ilə çökür.
Anlamaq vacibdir: @InjectMocks sahələrin tiplərini təhlil etmir — tipə uyğun gələn istənilən mock-u yerləşdirir. Sinifdə eyni tipdə iki sahə varsa — Mockito səhv mock-u yerləşdirə bilər. Belə hallarda mockların ötürülməsi ilə açıq konstruktordan istifadə etmək tövsiyə olunur.
Android inkişafında Mockito JUnit ilə birlikdə ViewModel, Repository və UseCase-in test edilməsi üçün istifadə olunur. Bu siniflər Android konteksti olmadan JVM-də işlədiyi üçün Mockito onların asılılıqlarını — Room DAO, Retrofit API, SharedPreferences — proqnozlaşdırıla bilən davranışlı stub-larla əvəz edir.
Mockito-nu Android layihəsinə əlavə etmək üçün mockito-core və ya mockito-inline asılılığını əlavə etmək kifayətdir (sonuncu final siniflərin və statik metodların mock edilməsini dəstəkləyir). 5.12.0 versiyası (2024) Java 21 dəstəyi və JUnit 5 ilə təkmilləşdirilmiş inteqrasiya daxildir.
// build.gradle.kts (modul)
dependencies {
testImplementation("org.mockito:mockito-core:5.12.0")
testImplementation("org.mockito:mockito-junit-jupiter:5.12.0")
}
Əvvəllər statik metodların və konstruktorların mock edilməsi üçün baytkod instrumentasiyası ilə işləyən PowerMock genişlənməsi tələb olunurdu. Mockito 5.x-dən mockito-inline ilə bu funksionallıq birbaşa daxil edilmişdir: mockStatic(ClassName.class) əlavə kitabxanalar olmadan statik metodları mock etməyə imkan verir.
Tipik ssenari: ViewModel repozitoriya metodunu çağırır və nəticəni UI vəziyyətinə çevirir. Mockito repozitoriyanı əvəz edir, test isə ViewModel-in uğurlu cavabı və xətanı düzgün emal etdiyini yoxlayır. Clean Architecture tətbiq edildikdə, hər təbəqə üçün mocklar yaradılır: DataSource, Repository və UseCase — bu, hər təbəqəni təcrid olunmuş şəkildə test etməyə imkan verir.
Tez-tez verilən suallar
Mockito — proxy və refleksiyadan istifadə edən Java və Kotlin üçün kitabxana. MockK — koroutine, genişləndirmə funksiyaları və final siniflərini əlavə konfiqurasiya olmadan dəstəkləyən Kotlin-first kitabxana.
Mockito 2.1-dən etibarən final siniflərin mock edilməsi opt-in vasitəsilə dəstəklənir. 5.x versiyasında (mockito-inline) bu standart olaraq aktivdir. Sadəcə mockito-inline asılılığını əlavə etmək və standart mock() metodundan istifadə etmək kifayətdir.
Spy — standart olaraq real metodları çağıran, lakin bəzilərini when().thenReturn() ilə əvəz etməyə imkan verən qismən mock-dur. Spy bütün sinfi yenidən yazmaq mümkün olmayan legacy-kodun test edilməsi üçün faydalıdır.
thenReturn arqumentlərdən asılı olmayaraq həmişə eyni dəyəri qaytarır. thenAnswer qaytarılan dəyəri invocation əsasında hesablayır — çağırış arqumentləri, mock-un özü, vəziyyət. Dinamik cavablar üçün həmişə thenAnswer istifadə edin.
Verify təkcə nəticəni deyil, həm də prosesi — asılılığa müraciət faktını yoxlayır. Bu, məlumatları saxlamalı və ya bildirişlər göndərməli olan xidmətlər üçün kritikdir. Verify olmadan test metodun save() və ya send() çağırmadığını aşkar etməyəcək.
Xülasə
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