Vahid testləri, bütöv sistemdən təcrid olunmuş şəkildə ayrı-ayrı modulların və ya funksiyaların düzgün işləməsini yoxlayan proqram təminatının yoxlanılması metodudur. Martin Fowler, 2026-ya görə, vahid testlər CI/CD və refaktorinqin təməlidir, kodun iş̧ləkliliyi haqqında sürətli əks əlaqə təmin edir. Modul testləri inkişafın erkən mərhələlərində səhvləri aşkarlamağa kömək edir, onların düzəldilmə xərcini dəfələrlə azaldır.
vacib
Vahid testlər proqram kodunun ayrı-ayrı vahidlərinin — funksiyaların, metodların, siniflərin — proqramın qalan hissəsindən təcrid olunmuş şəkildə yoxlanılması prosesidir. Hər bir test modulun müəyyən istifadə ssenarisini işə salır və nəticənin gözlənilənə uyğun olub-olmadığını yoxlayır. Vahid testlər əsas kodla eyni proqramlaşdırma dilində yazılır və inkişaf mühitində və ya CI/CD pipeline-də avtomatik yerinə yetirilir. nteqrasiya testlərindən fərqli olaraq, vahid testlər real verilənlər bazaları, fayl sistemi və ya şəbəkə xidmətləri ilə qarşılıqlı əlaqədə olmur.
sas məqsəd dəyişikliklərdən sonra kodun düzgünlüyü haqqında sürətli əks əlaqədir. Proqramçı metodu refaktorinq edərsə, vahid testlər dəsti davranışın pozulmadığını təsdiqləyir. Google Testing Blog (2025)-a görə, vahid testlərlə əhatəsi 60%-dən yuxarı olan layihələrdə istehsal hadisələri 2.5 dəfə az olur. lavə üstünlüklər: kod sənədləşdirməsi (testlər APIdan necə istifadə ediləcəyini göstərir), refaktorinqin sadələşdirilməsi (davranışı qoruyaraq tətbiqi dəyişmək olar) və reqressiyaların sürətli diaqnostikası.
Hər avtomatik test vahid test deyil. Meyarlar: bir modul (sinif və ya funksiya) test edilir, xarici asılılıqlar moklər və ya stabllarla əvəz edilir, test millisaniyələrdə yerinə yetirilir, server və ya verilənlər bazasının qaldırılmasını tələb etmir. Real verilənlər bazasına müraciət edən test inteqrasiya testidir. Brauzer açan test E2E testidir. Test növləri arasındakı sərhədləri başa düşmək test piramidasında səylərin düzgün paylanması üçün vacibdir.
Keyfiyyətli vahid testlər Robert C. Martin tərəfindən formalaşdırılmış FIRST prinsiplərinə əməl edir. Hər bir test Fast (sürətli — millisaniyələr), Isolated (təcrid olunmuş — digər testlərdən asılı deyil), Repeatable (təkrarlana bilən — istənilən maşında eyni nəticə), Self-validating (özünü yoxlayan — nəticə “passed” və ya “failed”, əl ilə yoxlama olmadan) və Timely (vaxtında — koddan əvvəl və ya eyni vaxtda yazılmalıdır) olmalıdır. Hər hansı bir prinsipin pozulması testin dəyərini azaldır.
Vahid testlərin yazılması üçün standart şablon. Arrange — məlumatların və asılılıqların hazırlanması: obyektlərin yaradılması, mokların qurulması, giriş parametrlərinin təyin edilməsi. Act — test edilən hərəkətin yerinə yetirilməsi: metodun və ya funksiyanın çağırılması. Assert — nəticənin yoxlanılması: faktiki dəyərin gözlənilənlə müqayisəsi. bloklara bölünmə testi oxunaqlı və başa düşülən edir. Assert bloku mürəkkəb məntiq tələb edərsə, test yəqin ki, bir dəfədə çox şey yoxlayır.
// Kotlin-də JUnit 5 ilə AAA şablonuna uyğun vahid test nümunəsi
class CalculatorTest {
private lateinit var calculator: Calculator
@BeforeEach
fun setUp() {
// ARRANGE — test edilən obyekti yaradırıq
calculator = Calculator()
}
@Test
fun addition_shouldReturnCorrectSum() {
// ACT — hərəkəti yerinə yetiririk
val result = calculator.add(2, 3)
// ASSERT — nəticəni yoxlayırıq
Assertions.assertEquals(5, result)
}
}
Testin adı nəyin yoxlanıldığını və hansı nəticənin gözlənildiyini təsvir etməlidir. Format: [methodName]_[scenario]_[expectedResult]. Nümunə: calculateTotal_whenDiscountApplied_shouldReturnDiscountedTotal. Yaxşı test adı şərhi əvəz edir və uğursuzluqda dərhal hansı funksionallığın pozulduğunu göstərir. test1, checkSomething və ya verify kimi adlardan çəkinin — onlar məlumat daşımır və diaqnostikanı çətinləşdirir.
Test edilən modulu xarici asılılıqlardan təcrid etmək üçün test dublerlərindən (test doubles) istifadə olunur. sas növlər: moklər (mocks) — müəyyən metodun düzgün parametrlərlə çağırıldığını yoxlayır; stablar (stubs) — metod çağırıldıqda müəyyən dəyərləri qaytarır; feyklər (fakes) — real komponentin sadələşdirilmiş tətbiqidir (məsələn, verilənlər bazası ilə işləyən UserRepository əvəzinə InMemoryUserRepository). Seçim nəyin yoxlanılmasından asılıdır: vəziyyət (stab) və ya qarşılıqlı əlaqə (mok).
| Dubler | Nə yoxlayır | Nümunə |
|---|---|---|
| Mok | Metodun düzgün parametrlərlə çağırılması | userRepository.save(user) tam 1 dəfə çağırıldı |
| Stab | Qaytarılan dəyər | repository.findById(1) User(id=1, name=“Test”) qaytarır |
| Feyk | Sadələşdirilmiş tətbiq vasitəsilə məntiq | Verilənlər bazası əvəzinə HashMap ilə InMemoryMapUserRepository |
| Kasıs | Real obyektin qismən moklanması | spy(repo).when(findById).thenReturn(user) |
Mockito Java və Kotlin-də moklama üçün ən məşhur freymvorkdur. mock() vasitəsilə moklar yaratmağa, when().thenReturn() vasitəsilə dəyərlərin qaytarılmasını konfiqurasiya etməyə və verify() vasitəsilə çağırışları yoxlamağa imkan verir. Mockito-nun müasir versiyaları (5.x) statik mokları (mockStatic) və BDDMockito (given-willReturn) vasitəsilə sadələşdirilmiş sintaksisi dəstəkləyir. Vacib qayda: sizə aid olmayanı moklamayın — dəyər obyektləri və standart kitabxanalar üçün moklar yaratmayın.
// Kotlin-də Mockito ilə vahid test nümunəsi
class OrderServiceTest {
@Mock
private lateinit var paymentGateway: PaymentGateway
@Mock
private lateinit var userRepository: UserRepository
private lateinit var orderService: OrderService
@BeforeEach
fun init() {
MockitoAnnotations.openMocks(this)
orderService = OrderService(paymentGateway, userRepository)
}
@Test
fun processOrder_whenPaymentFails_shouldThrowException() {
// given
val user = User(id = 1, balance = 100.0)
val order = Order(amount = 200.0)
Mockito.`when`(paymentGateway.charge(any())).thenReturn(false)
Mockito.`when`(userRepository.findById(1)).thenReturn(user)
// when & then
assert Throws<PaymentException> {
orderService.processOrder(user.id, order)
}
// verify
Mockito.verify(paymentGateway).charge(any())
}
}
TDD (Test-Driven Development) — testin kodun tətbiqindən əvvəl yazıldığı metodologiyadır. “Red-Green-Refactor” dövri: uğursuz test yaz (Red), testi keçmək üçün minimal kod yaz (Green), davranışı dəyişmədən kodu yaxşılaşdır (Refactor). TDD bütün kodun testlərlə əhatə olunmasını (yazılmış funksionallıq üçün əhatə = 100%) və kodun test edilə bilən olmasını təmin edir — kodu test etmək çətindirsə, bu, arxitekturanın təkmilləşdirilməyə ehtiyacı olduğunu göstərir.
IBM (2006-2026, uzunmüddətli tədqiqat)-nın məlumatlarına görə, TDD istifadə edən komandalar kodu yazdıqdan sonra test yazan komandalarla müqayisədə istehsalda 40-80% daha az qüsurlara yol verir. TDD həmçinin arxitekturanı yaxşılaşdırır: proqramçı tətbiqdən əvvəl API dizaynı haqqında düşünməli olur, bu da zəif birləşməyə (loose coupling) və yüksək əlaqəliliyə (high cohesion) səbəb olur. lavə effekt — canlı kodla sənədləşdirmə: testlər modulun hər zaman aktual olan davranış spesifikasiyası kimi xidmət edir.
TDD həmişə optimal deyil. UI komponentlərini təcriddə test etmək çətindir — onlar üçün snapshot testləri və ya vizual reqressiya testləri (Percy, Chromatic) daha təsirli olur. Prototipləşdirmə və tədqiqat (spike solutions) test tələb etmir. Testsiz legacy kodu TDD ilə əhatə etmək çétindir — burada refaktorinqdən əvvəl characterization tests (cari davranışı qeyd edən testlər) lazımdır. Bu hallarda TDD tamamilə ləğv edilmir, uyğunlaşdırılır — bütün legacy kod üçün deyil, dəyişdirilən funksionallıq üçün testlər yazılır.
Mobil inkişafın özəlliyi var: biznes məntiqi tez-tez UI kodu ilə qarışır (Activity, ViewController, ViewModel), bu da vahid testləri çətinləşdirir. n yaxşı təcrübə nazik görünüşlər, qalın ViewModel-lər: bütün məntiqi UI komponentlərindən emulyator olmadan asanlıqla test edilə bilən ayrı siniflərə (UseCase, Repository, ViewModel) köçürün. Android və iOS üçün cihazı işə salmadan JVM/Native-də işləyən yerli vahid test freymvorkları mövcuddur.
Android vahid testləri emulyator olmadan yerli JVM-də yerinə yetirilir, bu da icra sürətini təmin edir — tipik test 100ms-dən az çəkir. JUnit 5 əsas runnerdir. ViewModel testləri üçün korutinlərin test edilməsi üçün kotlinx-coroutines-test və StateFlow-un test edilməsi üçün Turbine istifadə edin. Robolectric shadow-sinifləri yükləyərək Androiddən asılı komponentləri (Context, Resources) emulyator olmadan test etməyə imkan verir. Compose testləri üçün Compose UI Test istifadə edin — lakin bunlar artıq vahid deyil, UI testləridir.
iOS vahid testləri Swift ilə XCTest-də (Xcode-a daxildir) yazılır. Quick + Nimble — daha oxunaqlı testlər üçün BDD freymvorkları (describe/context/it). Moklama üçün Cuckoo (mokların generasiyası) və ya SwiftyMocky istifadə edin. Swift protokolları və dependency injection-u dəstəkləyir, bu da asılılıqların dəyişdirilməsini asanlaşdırır. sas məqam: iOS vahid testləri real cihazda deyil, macOS simulyatorunda yerinə yetirilir. Avadanlıq funksiyaları (kamera, Bluetooth) tələb edən testlər inteqrasiya testləridir.
Flutter vahid testləri flutter_test paketindən istifadə edir və emulyator olmadan Dart VM-də yerinə yetirilir. Moklama üçün mockito paketi kod generatoru (build_runner) ilə birlikdə istifadə olunur. Vidjet testləri (eyni paketdə) ayrı-ayrı vidjetləri test edir, lakin render tələb edir və daha yavaş işləyir — onları yalnız UI məntiqini yoxlamaq üçün istifadə edin. Təmiz Dart məntiqi (modellər, repozitoriyalar, bloblarl flutter_test import etmədən adi Dart testləri kimi test edilir.
// Flutter-də mockito ilə vahid test nümunəsi
import 'package:flutter_test/flutter_test.dart';
import 'package:mockito/mockito.dart';
import 'package:mockito/annotations.dart';
@GenerateMocks([ApiClient])
import 'user_repository_test.mocks.dart';
void main() {
late MockApiClient mockApi;
late UserRepository repository;
setUp(() {
mockApi = MockApiClient();
repository = UserRepository(mockApi);
});
test('fetchUser returns user when API succeeds', () async {
// Arrange
final expectedUser = User(id: 1, name: 'Test');
when(mockApi.getUser(1))
.thenAnswer((_) async => expectedUser);
// Act
final result = await repository.fetchUser(1);
// Assert
expect(result, expectedUser);
verify(mockApi.getUser(1)).called(1);
});
}
Effektiv vahid testlər intizam tələb edir. sas qayda: davranışı test edin, tətbiqi deyil. Test modulun daxildə necə tətbiq edildiyini bilməməlidir (hansı özəl metodların çağırıldığı, hansı ardıcıllıqla). Test tətbiqə bağlıdırsa, hər refaktorinqdə qırılır və dəyərini itirir. Test kontraktı yoxlayır: X girişində Y çıxışı olmalıdır. stamana çağırış ardıcıllığının vacib olduğu kritik performanslı alqoritmlər üçün testlər istisnadır.
100% əhatə əlçatmaz və lazımsız məqsəddir. Google Testing Blog (2025)-a görə, vahid testlər üçün optimal əhatə səviyyəsi kod sətrlərinin 70-80%-dir. 100% əhatə tez-tez getterlərin, setterlərin və konstruktorların test edilməsi hesabına əldə edilir, bu da dəyər gətirmir. Kritik biznes məntiqinə diqqət yetirin: mürəkkəb hesablamalar, validasiya, səhv idarəetməsi, haşiyə halları. Ölçmək üçün JaCoCo (Java), Coverage.py (Python), Istanbul (JS) istifadə edin və CI-da hədd təyin edin — əhatə 60%-dən aşağı olduqda build-in çökməsi.
Vahid testlər istənilən CI/CD pipeline-nin ilk mərhələsidir. Onlar hər push-da, build və deploy-dan əvvəl yerinə yetirilir. Layihədə vahid testlərin orta işə salınma müddəti 5 dəqiqədən çox olmamalıdır — daha uzun olarsa, testlər “sürətli” olmaqdan çıxır və proqramçılar onları lokal olaraq işə salmağı dayandırır. Testləri sürətli (vahid) və yavaş (inteqrasiya) olaraq ayırın və onları pipeline-nin müxtəlif mərhələlərində işə salın. Sürətləndirmək üçün paralel icra və fail-fast istifadə edin.
Tez-tez verilən suallar
Vahid test bir modulu təcriddə yoxlayır, xarici asılılıqları moklarla əvəz edir. nteqrasiya testi bir neçə real komponentin (verilənlər bazası, API, fayl sistemi) qarşılıqlı əlaqəsini yoxlayır. Vahid testlər millisaniyələrdə, inteqrasiya testləri saniyələrdə yerinə yetirilir. Test piramidasında vahid testlər 70% təşkil edir.
Seçim platformadan asılıdır: Java/Kotlin üçün JUnit 5, iOS/Swift üçün XCTest, Python üçün pytest, JavaScript/TypeScript üçün Jest/Vitest, Flutter üçün flutter_test. Moklama üçün Mockito (Java), Cuckoo (iOS), unittest.mock (Python) və ya vitest.mock (JS) istifadə edin. Bütün müasir freymvorklar parametrləşdirilmiş testləri, daxili assertleri və paralel işə salmanı dəstəkləyir.
Fast — test millisaniyələrdə yerinə yetirilir. Isolated — digər testlərdən və xarici sistemlərdən asılı deyil. Repeatable — istənilən maşında eyni nəticəni verir. Self-validating — nəticəni avtomatik yoxlayır. Timely — koddan əvvəl və ya sinxron yazılır. Hər hansı bir prinsipin pozulması testin effektivliyini azaldır.
Bəli, məcburi. ViewModel biznes məntiqini ehtiva edir — hadisələrin işlənməsi, məlumatların transformasiyası, vəziyyətin idarə edilməsi. Android-də korutinlər üçün kotlinx-coroutines-test və StateFlow testi üçün Turbine istifadə edin. iOS-da ViewModel-də Combine Publishers və ya async/await test edin. ViewModel testləri emulyator olmadan JVM/macOS-də işləyən təmiz vahid testlərdir.
Veb sorğuları vahid testlərdə yerinə yetirilmir — onlar HTTP mokları ilə əvəz olunur. Android-də MockWebServer (OkHttp) istifadə edin — o, lokal HTTP serveri qaldırır, bu da moklardan daha üstündür, çünki real şəbəkə qarşılıqlı əlaqəsini əks etdirir. MockWebServer realizmi itirmədən təcrid təmin edir. iOS üçün — cavabların kəsişdirilməsi və dəyişdirilməsi üçün OHHTTPStubs və ya URLProtocol.
Nəticə
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