Test-Driven Development (TDD) ایک ترقیاتی طریقہ کار ہے جس میں کوڈ پر عملدرآمد سے پہلے ٹیسٹ لکھے جاتے ہیں۔ ڈویلپر پہلے متوقع رویے کو ناکام ٹیسٹ کی صورت میں مرتب کرتا ہے، پھر اسے پاس کرنے کے لیے کم سے کم کوڈ لکھتا ہے اور اس کے بعد نتیجہ کو ری فیکٹر کرتا ہے۔ Martin Fowler (2023) کے مطابق، TDD کوئی جانچ کی تکنیک نہیں ہے — یہ ایک ڈیزائن کی تکنیک ہے جو آرکیٹیکچر کو منضبط کرتی ہے اور کوڈ لکھنے کے مرحلے پر نقائص کی تعداد کو کم کرتی ہے۔
اہم نکات
Test-Driven Development ایک سافٹ ویئر ڈویلپمنٹ مشق ہے جس میں خودکار ٹیسٹ پروڈکشن کوڈ کی تحریر کا تعین کرتے ہیں۔ روایتی نقطہ نظر کے برعکس جہاں کوڈ لکھا جاتا ہے اور پھر جانچا جاتا ہے، TDD ترتیب کو الٹ دیتا ہے: پہلے ٹیسٹ لکھا جاتا ہے، پھر وہ کوڈ جو اس ٹیسٹ کو پاس کرتا ہے۔
TDD کے بانی Kent Beck کو سمجھا جاتا ہے، جس نے 1990 کی دہائی کے آخر میں Extreme Programming (XP) طریقہ کار کے حصے کے طور پر اس مشق کو تشکیل دیا۔ کتاب «Test-Driven Development: By Example» (2002) میں، بیک نے TDD کے پانچ اصولوں کو بیان کیا جو معیاری بن گئے: پروڈکشن کوڈ سے پہلے ٹیسٹ لکھیں، ٹیسٹ پاس کرنے کے لیے صرف اتنا کوڈ لکھیں جتنا ضروری ہو، اور ہر سائیکل کے بعد ری فیکٹر کریں۔
پہلا اصول — ٹیسٹ انٹرفیس کی وضاحت کرتا ہے۔ ڈویلپر کو یہ سوچنے پر مجبور کیا جاتا ہے کہ جزو کیسے استعمال ہوگا اس سے پہلے کہ وہ سوچے کہ اسے کیسے نافذ کیا جائے۔ یہ شروع سے ہی ایک صاف API تشکیل دیتا ہے۔
دوسرا اصول — کم سے کم عملدرآمد۔ جب ٹیسٹ لکھا جاتا ہے، ڈویلپر صرف اتنا پروڈکشن کوڈ لکھتا ہے جتنا اسے پاس کرنے کے لیے ضروری ہے — ایک لائن بھی زیادہ نہیں۔ یہ قبل از وقت تجرید اور ضرورت سے زیادہ پیچیدگی کو روکتا ہے، جسے Martin Fowler Speculative Generality کہتے ہیں۔
TDD اور «بعد میں» جانچ کے درمیان بنیادی فرق — ترتیب کا نظم و ضبط ہے۔ TDD میں، ٹیسٹ صرف کوڈ کی تصدیق نہیں کرتا — یہ اس کی ساخت کی رہنمائی کرتا ہے۔ Microsoft Research (Nagappan et al., 2008) کے مطالعے کے مطابق، TDD استعمال کرنے والی ٹیمیں روایتی نقطہ نظر استعمال کرنے والی ٹیموں کے مقابلے میں 40–90% کم نقائص کی کثافت ظاہر کرتی ہیں۔
Red-Green-Refactor سائیکل ایک تین مرحلوں پر مشتمل ترتیب ہے جو ہر نئے ٹیسٹ کے لیے دہرائی جاتی ہے۔ Red: ایک ٹیسٹ لکھیں جو پاس نہیں ہوتا۔ Green: ٹیسٹ پاس کرنے کے لیے کم سے کم کوڈ لکھیں۔ Refactor: رویے کو تبدیل کیے بغیر کوڈ کو بہتر بنائیں۔
ڈویلپر ایک ٹیسٹ لکھتا ہے جو ابھی تک نافذ نہیں کی گئی فعالیت کی تصدیق کرتا ہے۔ اس مرحلے پر، ٹیسٹ کو ناکام ہونا چاہیے — یہ تصدیق کرتا ہے کہ ٹیسٹ واقعی کسی چیز کی تصدیق کر رہا ہے۔ Android ڈویلپمنٹ ماحول میں، JUnit 5 فریم ورک ناکام ٹیسٹوں کے لیے سرخ اشارہ دکھاتا ہے، جس نے اس مرحلے کو نام دیا۔
class CalculatorTest {
fun testAddition() {
val result = Calculator().add(2, 3)
Assertions.assertEquals(5, result)
}
}
اس مرحلے پر، ٹیسٹ پاس کرنے کے لیے کافی کم سے کم پروڈکشن کوڈ لکھا جاتا ہے۔ کوئی ضرورت سے زیادہ نہیں — صرف وہی جو سبز اشارے کے لیے ضروری ہے۔ اگر عملدرآمد ایک مستقل ہو سکتا ہے، تو اسے مستقل رہنے دیں۔ ری فیکٹرنگ اگلے مرحلے پر ہوگی جب نئے ٹیسٹ سامنے آئیں گے۔
class Calculator {
fun add(a: Int, b: Int): Int {
return a + b
}
}
سبز ٹیسٹ ری فیکٹرنگ کے لیے بیمہ ہے۔ ڈویلپر عملدرآمد کو دوبارہ لکھ سکتا ہے، کارکردگی کو بہتر بنا سکتا ہے یا پڑھنے کی اہلیت کو بہتر بنا سکتا ہے، اس اعتماد کے ساتھ کہ ٹیسٹ فوری طور پر متوقع رویے سے کسی بھی انحراف کا پتہ لگائے گا۔ Android موبائل ڈویلپمنٹ میں، یہ مرحلہ مشترکہ انٹرفیس نکالنے اور کوڈ کی تکرار کو کم کرنے کے لیے خاص طور پر اہم ہے۔
موبائل پروجیکٹس میں TDD کا اطلاق قابل پیمائش فوائد دیتا ہے، جو تعلیمی تحقیق اور معروف ڈویلپمنٹ اسٹوڈیوز کی مشق دونوں سے تصدیق شدہ ہیں۔
چار صنعتی پروجیکٹس پر IBM کا مطالعہ (Bhat & Nagappan, 2006) نے دکھایا کہ TDD استعمال کرنے والی ٹیمیں روایتی طریقے پر کام کرنے والی مماثل ٹیموں کے مقابلے میں 40% کم نقائص پیدا کرتی ہیں۔ موبائل ڈویلپمنٹ کے لیے، جہاں Google Play پر ریلیز کے بعد بگ کو ٹھیک کرنے کی لاگت کوڈ لکھنے کے مرحلے کے مقابلے میں کافی زیادہ ہوتی ہے، یہ میٹرک اہم ہے۔
TDD کے ساتھ لکھے گئے ٹیسٹ API کی زندہ دستاویزات کے طور پر کام کرتے ہیں۔ پروجیکٹ میں شامل ہونے والا ڈویلپر ٹیسٹ پڑھ سکتا ہے اور سمجھ سکتا ہے کہ ہر جزو کو کیسے استعمال کیا جانا چاہیے۔ یہ ٹیم کی زیادہ تبدیلی کی صورتحال میں خاص طور پر قیمتی ہے — موبائل اسٹوڈیوز کا ایک عام چیلنج۔
90% سے تجاوز کرنے والی کوڈ کوریج ڈویلپرز کو کچھ توڑنے کے خوف کے بغیر ری فیکٹر کرنے کی اجازت دیتی ہے۔ Google اپنی کتاب «Software Engineering at Google» (2020) میں ٹیسٹ کوریج کو لاکھوں لائنوں والے پروجیکٹس میں کوڈ بیس کو صاف رکھنے کا اہم عنصر قرار دیتا ہے۔
موبائل ڈویلپمنٹ میں TDD ایکو سسٹم میں یونٹ ٹیسٹنگ، موکنگ اور UI اجزاء کی تصدیق کے ٹولز شامل ہیں — Android اور iOS دونوں کے لیے۔
| ٹول | پلیٹ فارم | مقصد |
|---|---|---|
| JUnit 5 | Android (Kotlin/Java) | یونٹ ٹیسٹ کے لیے بنیادی فریم ورک |
| Mockito | Android | موک آبجیکٹ بنانا اور کالز کی تصدیق |
| MockK | Android (Kotlin) | Kotlin-first نحو اور coroutine کی حمایت کے ساتھ موکنگ |
| Turbine | Android | Kotlin Flow اور ری ایکٹیو سٹریمز کی جانچ |
| XCTest | iOS (Swift) | معیاری جانچ کا فریم ورک |
Kotlin پر Android پروجیکٹس کے لیے، معیاری اسٹیک میں JUnit 5 + MockK شامل ہے۔ MockK، Mockito سے بہتر ہے کیونکہ یہ بغیر اضافی ترتیب کے Kotlin کی فرسٹ کلاس خصوصیات — sealed class، coroutine اور suspend functions — کو سپورٹ کرتا ہے۔
iOS ڈویلپمنٹ میں، TDD کو XCTest کے ذریعے نافذ کیا جاتا ہے — Apple کا بلٹ ان فریم ورک جو اثبات (assertions)، ٹیسٹ کلاسز اور Xcode Server یا GitHub Actions کے ذریعے CI/CD انضمام فراہم کرتا ہے۔ iOS پر موکنگ کے لیے Cuckoo اور OHHTTPStubs لائبریریاں استعمال ہوتی ہیں۔
Android کے لیے Kotlin میں TDD کا ایک حقیقی منظرنامہ دیکھتے ہیں — صارفین کے ریپوزٹری کی جانچ۔ پہلے ہم ٹیسٹ لکھتے ہیں، پھر وہ عملدرآمد جو اس ٹیسٹ کو پاس کرتا ہے۔
class UserRepositoryTest {
private val api = mockk<UserApi>()
private val dao = mockk<UserDao>()
private val repo = UserRepository(api, dao)
fun `when api returns user then cache and emit`() = runTest {
val user = User(1, "Alice")
coEvery { api.getUser(1) } returns user
every { dao.insert(user) } returns Unit
val result = repo.getUser(1)
assertEquals(user, result)
verify { dao.insert(user) }
}
}
class UserRepository(
private val api: UserApi,
private val dao: UserDao
) {
suspend fun getUser(id: Int): User {
val user = api.getUser(id)
dao.insert(user)
return user
}
}
پہلا ٹیسٹ پاس کرنے کے بعد، ہم دوسرا ٹیسٹ شامل کرتے ہیں — نیٹ ورک کی خرابی پر رویے کی تصدیق کرتے ہیں۔ اب ٹیسٹ طے کرتا ہے کہ جب API ناکام ہوتا ہے، ریپوزٹری کو کیشے سے ڈیٹا واپس کرنا چاہیے۔
fun `when api fails then return cached user`() = runTest {
val cached = User(1, "Cached Alice")
coEvery { api.getUser(1) } throws IOException()
every { dao.getById(1) } returns cached
val result = repo.getUser(1)
assertEquals(cached, result)
}
TDD میں منتقلی عام غلطیوں سے وابستہ ہے جو طریقہ کار کے تمام فوائد کو ختم کر سکتی ہیں۔ ان جالوں کو سمجھنا ٹیموں کو مشق کو زیادہ مؤثر طریقے سے اپنانے میں مدد کرتا ہے۔
پہلا اور سب سے عام اینٹی پیٹرن — ایک ٹیسٹ میں فعالیت کی بہت بڑی مقدار کی جانچ کرنا۔ ٹیسٹ کو بالکل ایک دعوے کی تصدیق کرنی چاہیے۔ اگر ٹیسٹ ناکام ہوتا ہے، تو ڈویلپر کو اضافی ڈیبگنگ کے بغیر معلوم ہونا چاہیے کہ بالکل کیا ٹوٹا۔
دوسری غلطی — ایسا ٹیسٹ لکھنا جو شروع سے ہی پاس ہوتا ہے۔ اگر ٹیسٹ کم از کم ایک بار سرخ نہیں ہوا، تو کوئی یقین نہیں کہ یہ واقعی کسی چیز کی تصدیق کر رہا ہے۔ قاعدہ: کبھی بھی اس ٹیسٹ پر بھروسہ نہ کریں جسے آپ نے ناکام ہوتے نہیں دیکھا۔
تیسری عام غلطی — سبز مرحلے پر رک جانا۔ ری فیکٹرنگ اختیاری نہیں بلکہ سائیکل کا لازمی مرحلہ ہے۔ اس کے بغیر، کوڈ بیس خراب ہوتا ہے، ٹیسٹ نازک ہو جاتے ہیں، اور TDD کے فوائد کھو جاتے ہیں۔
اکثر پوچھے گئے سوالات
TDD سب سے پہلے ڈیزائن کی تکنیک ہے، جانچ کی تکنیک نہیں۔ TDD میں ٹیسٹ ایک تصریح کا کردار ادا کرتے ہیں: وہ عملدرآمد سے پہلے جزو کے API کی وضاحت کرتے ہیں۔ خود Kent Beck TDD کو «ڈیزائن کا نظم و ضبط کہتے ہیں، جانچ کا نہیں»۔
Microsoft Research کے مطالعات کے مطابق، ٹیموں کو TDD کو عادت بنانے کے لیے 3 سے 6 ماہ کے مسلسل مشق کی ضرورت ہوتی ہے۔ پہلے 2–3 ہفتوں میں پیداوری 15–30% گر جاتی ہے، لیکن موافقت کے بعد یہ ڈیبگنگ کے وقت میں کمی کی بدولت اصل سطح پر واپس آ جاتی ہے یا اس سے تجاوز کر جاتی ہے۔
ہاں، لیکن حدود کے ساتھ۔ UI منطق (ViewModel, State) کے لیے، TDD براہ راست قابل اطلاق ہے۔ بصری اجزاء (Compose UI, SwiftUI Views) کے لیے، سنیپ شاٹ ٹیسٹنگ TDD کی تکمیل کرتی ہے لیکن اسے تبدیل نہیں کرتی۔ کاروباری منطق اور ڈسپلے کو الگ کرنے کی سفارش کی جاتی ہے۔
پرانی کوڈ کے لیے، «خاصیت کے ٹیسٹ» (characterization tests) کی حکمت عملی تجویز کی جاتی ہے — جہاں موجودہ رویے پر ٹیسٹ لکھے جاتے ہیں، اور پھر کوڈ ری فیکٹر کیا جاتا ہے۔ یہ نقطہ نظر Michael Feathers کی کتاب «Working Effectively with Legacy Code» (2004) میں بیان کیا گیا ہے اور TDD کو بتدریج لاگو کرنے کی اجازت دیتا ہے۔
TDD اور Clean Architecture ایک دوسرے کو تقویت دیتے ہیں۔ صاف آرکیٹیکچر کو تہوں کے درمیان واضح حدود کی ضرورت ہوتی ہے، اور TDD ڈویلپر کو ٹیسٹوں کے ذریعے ان حدود کو ڈیزائن کرنے پر مجبور کرتا ہے۔ ڈومین تہہ کو موک ڈیپنڈنسیز کے ساتھ الگ تھلگ کر کے جانچا جاتا ہے، ڈیٹا تہہ کو — انضمام کے ٹیسٹوں کے ذریعے۔
خلاصہ
ہم ایک موبائل ایپلیکیشن ٹرنکی تیار کریں گے
IT Sectr 2017 سے اسٹارٹ اپس اور کاروبار کے لیے iOS اور Android ایپلیکیشنز بناتا ہے۔ ہم آپ کو مشورہ دیں گے اور بہترین حل تجویز کریں گے۔
مزید پڑھیں