Test-driven Development (သို့) ပြဿနာ ကြိုရှာသူ

ပြီးခဲ့တဲ့ သောကြာနေ့က ကိုအိမောင်ရဲ့ ကျေးဇူးနဲ့ ပွဲတစ်ခု တက်ဖြစ်ခဲ့ပါတယ်။ MCPA ရဲ့ အစည်းအဝေး ခန်းမမှာပါ။ အဲဒီမှာ အဓိက ဟောပြောသူက ကိုရန်နောင်ပါ။ ဟောပြောသွားတဲ့ အကြောင်းအရာက TDD လို့ အမည်ရတဲ့ Test-Driven Development အကြောင်းပါ။ ကိုရန်နောင် ဟောပြောသွားတဲ့ ပုံစံက တကယ့်ကို ပေါ့ပေါ့ပါးပါး ရင်းရင်းနှီးနှီးရှိလှပါတယ်။ ဒါပေမယ့် ကျွန်တော်နဲ့ မရင်းနှီးတဲ့ Topic တစ်ခု ဖြစ်နေတာကြောင့် တော်တော်လေးကို အာရုံစိုက်ပြီး နားထောင်ခဲ့ရပါတယ်။ အဓိက ဖြစ်နေတဲ့ ပြဿနာက လက်တွေ့နဲ့ တွဲပြီး မသိနိုင်တဲ့ ပြဿနာပါ။ ကိုရန်နောင် ပြောသွားတာတွေကို အာရုံ့စိုက်နားထောင်ရင် ကျွန်တော့်မှာ ဒီထက်ဖိုပိုပြီး သိချင်စိတ်တွေ ပိုများလာပါတယ်။

အကြမ်းအားဖြင့် နားလည်လိုက်တာက ကိုယ်ရေးနေတဲ့ Code ကို တစ်ခါတည်း မှားလားမှန်းလား သိနေခွင့်ရမယ့် အနေအထားဆိုတော့ ပြောရရင် စမ်းတစ်ဝါးဝါး လမ်းလျောက်နေတာမျိုး မဟုတ်တော့ပဲ ရဲရဲတင်းတင်းလျောက်လို့ရမယ့် အနေအထားဆိုတော့ စိတ်ဝင်စားစရာလည်း အင်မတန်ကောင်းပါတယ်။ ကိုရန်နောင်ကတော့ ကြိုးတန်းပေါ် လမ်းလျောက်တာနဲ့ ဥပမာပေးသွားပါတယ်။ အောက်မှာ ပိုက်ခံထားတဲ့အခါ ရဲရဲတင်းတင်း လျောက်နိုင်တာပေါ့လို့ ဥပမာပေးသွားပါတယ်။ ကျွန်တော် ပြန်လာတော့ ခေါင်းထဲမှာ မေးခွန်းတွေ တစ်လှေကြီးဖြစ်နေပါတယ်။ TDD ဆိုတာဘာလဲ၊ Refactoring ဆိုတာ ဘာလဲ။ Mock ဆိုတာကရော ဘယ်လိုသုံးလဲ။ သိချင်စိတ်တွေ တစ်ဖွားဖွားပေါ်လာပါတယ်။ ကိုရန်နောင်ရဲ့ Presentation Slide ကိုတော့ ခွင့်ပြုချက်ရယူပြီး ပြန်တင်ပေးပါ့မယ်။

အဲဒီလိုနဲ့ အွန်လိုင်းမှာ လိုက်ရှာတော့ ကျွန်တော် သဘောအကျဆုံး Site တစ်ခုဖြစ်တဲ့ NetTuts Plus မှာ သွားတွေ့ပါတယ်။ ရေးထားတဲ့ ခေါင်းစဉ်ကလည်း The Newbie’s Guide to Test-Driven Development ဆိုတဲ့ ခေါင်းစဉ်နဲ့ပါ။ ဖတ်ကြည့်ပြီးတော့ ကျွန်တော် အတော်လေးကို သဘောကျမိပါတယ်။ အဲဒါနဲ့ ဒီပို့စ်ကို ရေးဖြစ်သွားတာပါ။ အဲဒီလို သိချင်စိတ်တွေ ဖြစ်ပေါ်လာအောင် ဖန်တီးပေးတဲ့ ကိုရန်နောင်ကို ကျေးဇူးအများ ကြီးတင်ပါတယ်။ အကိုသာ မျက်စိမဖွင့်ပေးခဲ့ရင် ကျွန်တော့်မှာ Ignorance အဆင့်က တက်မယ် မထင်ပါဘူး။ ခုလိုမျိုး မျက်စိဖွင့်ပေးတဲ့အတွက် TDD အကြောင်းကို သိခွင့် Knowledge ဖြစ်ခွင့်ရခဲ့တာပါ။ ရှေ့ဆက်ပြီး ပညာအဖြစ် အသုံးချနိုင်အောင် ကြိုးစားပါဦးမယ်။

Test-Driven Development ဆိုတာဘာလဲ

Computer ဆိုတာ စပေါ်လာကတည်းက Program နဲ့ Bugs ဆိုတာ စစ်တိုက်နေရသလိုပါပဲ။ သူက နိုင်သွားလိုက် ကိုယ်က နိုင်လိုက်နဲ့ တစ်နေ့တစ်နေ့ နဘန်းလုံး နေရတတ်ပါတယ်။ ဘယ်လိုမှ ရှောင်လွဲလို့ မရနိုင်တဲ့ ကိစ္စဖြစ်ပါတယ်။ Programmer တစ်ယောက် အနေနဲ့ ဘယ်လောက်အထိ ပျံလန်နေအောင် ကျွမ်းကျင်ပါစေ ဘယ် code မှ Safe မဖြစ်ဘူး။ Complete Error Free မဖြစ်ဘူးလို့ လက်ခံထားကြပါတယ်။ ဒါကြောင့် ကျွန်တော်တို့အနေနဲ့ Program တွေကိုရေးတဲ့ Testing (မှန် မမှန်စစ်)လုပ်ကြရပါတယ်။ စစ်ဆေးတယ်ဆိုတာ သိပ်ပြီးထူးထူးခြားခြာကိစ္စတော့ မဟုတ်ပါဘူး။ ကိုယ်ရေးတဲ့ Program က ကိုယ်ဖြစ်စေချင်တဲ့အတိုင်း ဖြစ်မဖြစ် အလုပ်လုပ်မလုပ်ဆိုတာ စစ်ဆေးတာပါပဲ။ ဒီဖက်က ဒါတွေ၊ ဒါတွေထည့်လိုက်တယ်။ ဟိုဖက်မှာ ဒါတွေဒါတွေထွက်လာတယ်။ အဲဒီလို Black Box Testing လို့ခေါ်တဲ့ Input နဲ့ Output ကိုသာ ကြည့်ပြီး စစ်ဆေးတာမျိုးလည်းရှိသလို White Box Testing လို့ခေါ်တဲ့ Program အတွင်းမှာ လုပ်ဆောင်သွားတဲ့ လုပ်ဆောင်ချက်တွေ အားလုံးကို စစ်ဆေးတာမျိုးလည်း ဖြစ်နိုင်ပါတယ်။ သေချာတာ တစ်ခုကတော့ Program တစ်ခုကို အစကနေ အဆုံးအထိ ရေးပြီးမှ Module အလို အစိတ်အပိုင်းအလိုက် ချိတ်ဆက်ပြီးမှ စစ်ဆေးတတ်ကြပါတယ်။ စစ်ဆေးလို့ရကြတာ များပါတယ်။

အဲဒီလို Testing လုပ်တဲ့ ပုံစံတွေက Batch Testing လို့ခေါ်လို့ရမယ် ထင်ပါတယ်။ နောက်ဆုံးမှ စစ်တယ် ဆိုပါတော့။ TDD ကတော့ အဲဒီလို မဟုတ်ပါဘူး။ Real-time Testing လို့ ပြောလို့ရနိုင်ပါတယ်။ Code နဲ့ Test တစ်ပြိုင်တည်း လုပ်သွားတာပါ။ actual code လို့ခေါ်တဲ့ ကိုယ်တကယ်ရေးနေတဲ့ Code ရယ်၊ နောက် Automated Test Code လို့ခေါ်တဲ့ Actual Code ကို စစ်ပေးမယ့် Code ကို တစ်ပြိုင်တည်း ရေးသွားတဲ့ ပုံစံကို ခေါ်ပါတယ်။ တစ်ခါတည်းရေး တစ်ခါတည်း စစ် ဆိုပါတော့။

TDD ဘယ်လို အလုပ်လုပ်သလဲ

TDD အနေနဲ့ Development Cycle လို့ခေါ်တဲ့ Code ရေးတဲ့ ဖြစ်စဉ်တစ်ခုမှာ အထပ်ထပ်လုပ်နေရတဲ့ ဖြစ်စဉ် တစ်ခုအတွင်းမှာ ပေါင်းထည့်ရတဲ့ Code တွေကို စစ်ပေးတဲ့ အစိတ်အပိုင်းတစ်ခု ဖြစ်ပါတယ်။

  1. ဘာ Code မှ စမရေးသေးခင်မှာ ကိုယ်ရေးမယ့် code အတွက် အလိုအလျောက် စစ်ပေးနိုင်မယ့် Code ကို အရင်ရေးရမှာ ဖြစ်ပါတယ်။ အဲဒီလို အလိုအလျောက် စစ်ပေးတဲ့ code ကို ရေးနေစဉ်အတွင်းမှာ ဖြစ်နိုင်ချေရှိသမျှ Inputs တွေ Errors တွေနဲ့ Outputs တွေအားလုံးကို အသေးစိတ် ရယူထားဖို့ လိုအပ်ပါတယ်။ လွယ်လွယ် ပြောရရင်တော့ ဘာတွေထည့်ရမယ်၊ ဘာတွေ မှားမယ်၊ ဘာတွေ ထွက်လာမယ် ဆိုတဲ့ အပိုင်းကို အသေအချာ သိအောင် လုပ်ထားတာပါပဲ။ အဲဒီလို သိထားခြင်းအားဖြင့် ကိုယ်ဘာတွေ လုပ်ရမယ်၊ ဘာတွေ လိုချင်နေတယ် ဆိုတာ Code စရေးကတည်းက သိနေပါလိမ့်မယ်။
  2. ပထမဦးဆုံး automated test ကို run လိုက်တာနဲ့ သေချာပေါက် ဖြစ်မှာကတော့ Fail ပါ။ စစ်တာ မအောင်ဘူးပေါ့။ မမှန်ဘူးပေါ့။ ဒါပေမယ့် အဲဒီလို ပထမဦးဆုံး စစ်တဲ့အချိန်မှာ ဘာ code မှာ မရေးရသေးတော့ ဘာမှ မှန်စရာ အကြောင်းလည်း မရှိပါဘူး။
  3. အဲဒီနောက်မှာ Program စရေးလို့ရပါပြီ။ ဒါပေမယ့် ကိုယ့်မှာက အလိုအလျောက်စစ်ပေးနိုင်တဲ့ စနစ်က ရှိပြီးသား။ ရေးလိုက် စစ်လိုက်၊ စစ်လိုက် ရေးလိုက်နဲ့ စစ်တာ မအောင်မချင်း၊ မမှန်မချင်း ဆက်ရေးရပါမယ်။ Fail ဖြစ်နေသမျှ ကာလပတ်လုံး code က ready မဖြစ်သေးဘူးဆိုတာ ပြနေပါတယ်။ code ကို နောက်ဆုံးမှာ Automated Test ကနေ လွတ်ထွက်သွားတဲ့အထိ ရေးရပါမယ်။
  4. နောက်ဆုံးမှာ Automated Test ကနေ Pass ဖြစ်သွားတဲ့ အခြေအနေ အောင်သွားတဲ့ အခြေအနေ မှန်သွားတဲ့ အခြေအနေ ရောက်လာပါမယ်။ ဒါဆိုရင် ရှေ့ဆက်ပြီး Cleaning Up လုပ်ရပါမယ်။ သန့်ရှင်းရေးပေါ့။ ဒီနေရာမှာ ကိုရန်နောင်ရဲ့ ဥပမာနဲ့ ပြောရမယ်ဆိုရင် တိုက်တော့ ဆောက်ပြီးသွားပြီ။ ဘိလပ်မြေအကြွင်းအကျန်တွေ အမှိုက်တွေ ရှင်းရမယ့် အနေအထားပါ။ အဲဒီလို ရှင်းလင်းရေး လုပ်တဲ့နေရာမှာ code တွေကို စနစ်ကျအောင် နာမည်ပေးတာ၊ မလိုတာတွေ ဖြုတ်တာ၊ မှီခိုနေတာတွေကို ခွဲထုတ်တာ စသည်ဖြင့် ပါဝင်ပါတယ်။ အဲဒီလို လုပ်တဲ့ အဆင့်ကို Refactoring လုပ်တယ်လို့ ခေါ်ပါတယ်။ ဒါပေမယ့် ဒီနေရာမှာ ကိုယ့်အနေနဲ့ စိတ်ချလို့ရတာ တစ်ခုကတော့ Automated Test မှာ Pass ဖြစ်နေသမျှ ကာလပတ်လုံး ကိုယ့် Code၊ ကိုယ့် Program အလုပ်ဖြစ်တယ်လို့ ယုံကြည်လို့ရတာပါပဲ။ သန့်ရှင်းရေးလုပ်တယ်ဆိုတာ ပြန်ပြင်တာ မဟုတ်တဲ့အတွက် Bugs တွေ အမှားတွေကို ပူစရာ မလိုတော့ပါဘူး။
  5. အဲဒီလို Program အစိတ်အပိုင်းတစ်ခု ပြီးသွားရင် နောက်တစ်ခုကို ဆက်ပြီး ရေးပါ။ နောက်ထပ် Module တစ်ခု Program တစ်ခုကို စပါ။

TDD က သာမန် Testing တွေထက် ဘာကောင်းလဲ

ကျွန်တော်တို့ အနေနဲ့ Testing လုပ်ရတာတွေကို အောက်ပါ ရည်ရွယ်ချက်တွေနဲ့ ကျော်သွားတတ်ကြပါတယ်။

  • Testing လုပ်ရတာ အချိန်ကုန်တယ်၊ တကယ်တန်းက code လေး နည်းနည်းပဲ ပြင်ရတာပါ။
  • Testing လုပ်ရတာ ပျင်းစရာကောင်းလိုက်တာ။
  • အချိန်က မလောက်တော့ဘူး၊ Project Manager က Production ကို တတ်နိုင်သမျှ အမြန်ဆုံး လုပ်ဖို့ တွန်းအားပေးနေပြီ။
  • တစ်ခြားကိစ္စတွေမှာ စိတ်များပြီး Testing မလုပ်ချင်တော့တာ။

ကိုယ့် အနေနဲ့ Coding တွေ ရေးနေတဲ့ အချိန်မှာ မစစ်ထားတော့ ဘာမှ မမှားဘူး။ အကုန်မှန်နေတယ်။ Production လုပ်တဲ့ အချိန်ကျမှ Customer ဆီကို ပေးတဲ့အခါကျမှ အားလုံးက မှားနေတာတွေ တွေ့ရပါတော့တယ်။ အဲဒီအချိန်မှာ ဘာနဲ့တူလဲဆိုရင် လှေကို ရေချပြီးမှ အပေါက်တွေ အများကြီးဖြစ်လာလို့ လိုက်ဖာရသလို ဖြစ်လာပါတယ်။ နောက်ဆုံးမှာ အခန့်မသင့်ရင် လှေနစ်သွားတဲ့အထိ ဖြစ်သွားနိုင်ပါတယ်။ အဲဒီအချိန်ရောက်လာရင် အရပ်ကူပါ လူဝိုင်းပါနဲ့ ကိုယ်ရေးထားတဲ့ Program ကို ပြန်နားမလည်နိုင်တော့တဲ့ ကိန်းဆိုက်ပါတော့တယ်။

TDD ကတော့ အဲဒီလို အဖြစ်မျိုးတွေကို ရှောင်လွဲနိုင်ဖို့အတွက်ပါ။ အကယ်၍များ ကျွန်တော်တို့ အနေနဲ့ Program တစ်ခုကို TDD သုံးပြီး တည်ဆောက်ထားမယ်ဆိုရင် တစ်ခုခုပြောင်းလဲဖို့ လိုအပ်တဲ့အခါမှာ အလွယ်တကူ ထိထိရောက်ရောက် ပြောင်းလဲပေးနိုင်မှာ ဖြစ်ပါတယ်။ TDD ကို ဒီထက်ပို နားလည်အောင် ဥပမာ ပေးရမယ်ဆိုရင် အင်္ကျီချုပ်တဲ့ လုပ်ငန်းလိုပါပဲ။ လက်ချုပ်တဲ့အပိုင်းမှာ Qualitiy Control လို့ခေါ်တဲ့ စစ်ဆေးရေးအပိုင်းကို ထား၊ ကျောဖက်ချုပ်တဲ့နေရာမှာ QC ထား စသည်ဖြင့် အစိတ်အပိုင်း တစ်ခုစီ၊ တစ်ခုစီ စစ်ဆေးရေးတွေ ထားပေးမယ်ဆိုရင် နောက်ဆုံး ထွက်လာတဲ့ အင်္ကျီအတွက် စစ်စရာ အင်မတန် နည်းသွားပါတော့တယ်။

အဲဒီလိုဖြစ်ဖို့အတွက် ကျွန်တော်တို့တွေဟာ အလိုအလျောက် စစ်ပေးတဲ့ စနစ်ကို Program ရေးစဉ်မှာ အသုံးချဖို့လိုပါတယ်။ အဲဒါ TDD ပါပဲ။ အလိုအလျောက်စစ်ပေးတဲ့ စနစ်ကနေ အောင်နေသမျှ ကာလပတ်လုံး ကျွန်တော်တို့ Program အလုပ်ဖြစ်နေတယ်၊ အလုပ်လုပ်နေတယ်လို့ ယုံကြည်နေလို့ရပါတယ်။ မအောင်တော့ဘူး ဆိုတာနဲ့ တစ်နေရာရာမှာတော့ ပြောင်းလိုင်တာ လွဲသွားပြီ၊ မှားသွားပြီဆိုတာ အလိုလို သိနေစေပါတယ်။ အဲဒီလို သိတဲ့နေရာမှာလည်း Program တစ်ခုလုံးပြီးမှ Software တစ်ခုလုံး ပြီးမှ သိတာမျိုးမဟုတ်ပဲ အစိတ်အပိုင်းအလို တစ်ခုချင်းစီကို သိနေပါတယ်။ အဲဒီအတွက် ပြင်ရတဲ့အခါမှာလည်း ပိုပြီး လွယ်ကူစေပါတယ်။

TDD ကတော့ ဟုတ်ပါပြီ၊ ဘယ်လိုလုပ်ရမှာလဲ

ဒီနေရာမှာတော့ TDD အတွက် PHPUnit ဆိုတဲ့ Framework တစ်ခုကို ညွှန်းလိုပါတယ်။ တကယ်တန်းတော့ TDD နဲ့ ပတ်သက်ပြီး PHP Framework တွေ အများကြီးရှိပါတယ်။ PHPUnit ကတော့ အသုံးအများဆုံး TDD Framework တစ်ခု ဖြစ်ပါတယ်။ တစ်ခြား Programming Language တွေအတွက်လည်း သူ့သက်ဆိုင်ရာနဲ့သူ ရှိနေမှာ ဖြစ်ပါတယ်။

PHPUnit ဆိုတာကတော့ တကယ့်ကို ကောင်းမွန်ပြည့်စုံတဲ့ Testing Framework တစ်ခု ဖြစ်ပြီး ကိုယ့်ရဲ့ Porject မှာ အလွယ်တကူ ပေါင်းထည့်လို့ရပါတယ်။ အဲဒီအပြင် အခြား PHP Framework တွေနဲ့လည်း အလွယ်တကူ ပေါင်းစပ်လို့ရနိုင်ပါတယ်။

အကယ်၍ ကိုယ့်ရဲ့ PHP Program ဟာ သိပ်မရှုပ်ဘူးဆိုရင်တော့ SimpleTest ဆိုတာကို သုံးနိုင်ပါတယ်။ ပိုပြီးရှင်းရှင်းလင်းလင်း ရှိသလို Function တွေ သိပ်မရှုပ်တဲ့ Program တွေမှာ သုံးနိုင်ပါတယ်။

ရှေ့ဆက်သွားမယ့် အပိုင်းကတော့ TDD ကို လက်တွေ့မှာ အသုံးချကြည့်တဲ့ အပိုင်းဖြစ်ပါတယ်။ Guestbook Application တစ်ခု တည်ဆောက်ကြည့်ပြီး TDD နဲ့ ချိတ်ဆက်ကြည့်မှာ ဖြစ်ပါတယ်။

GuestBook Application မှာ Guestbook တွေ ထည့်လို့ရမယ်၊ ကြည့်လို့ရမယ်၊ လောလောဆယ် Markup တွေကလည်း အားလုံးပြီးနေပြီ၊ Guestbook မှာပါတဲ့ Application Logic လို့ခေါ်တဲ့ တကယ့် Program ကို အဓိက မောင်းနှင်ပေးမယ့် Class ကိုလည်း တည်ဆောက်မယ်။ အဲဒီ Class မှာ Database ကို သွားထည့်မယ့် (Insert)၊ ပြန်ဖတ်မယ် (Read) စတာတွေ ပါဝင်ပါမယ်။ အဲဒီတော့ ကျွန်တော်တို့ စစ်မယ့် အပိုင်းက ဖတ်တဲ့အပိုင်း Read လုပ်တဲ့အပိုင်း ဆိုပါတော့။

အဆင့် (၁) SimpleTest ကို စတင်ခြင်း

SimpleTest ကို ဒီနေရာမှာ သွားပြီး Download ချလိုက်ပါ။ ပြီးရင် ကိုယ် ထည့်ချင်တဲ့ နေရာမှာ ထည့်လိုက်ပါ။ ဖြစ်နိုင်ရင် ကိုယ် Develop လုပ်နေတဲ့ Folder ထဲမှာ Zip ဖိုင်ကို ဖြည်လိုက်ပါ။ အဲဒီလို ဖြည်လိုက်တယ်ဆိုရင် အောက်မှာ ပြထားတဲ့အတိုင်း တွေ့ရမှာ ဖြစ်ပါတယ်။

index.php က guestbook.php ကို Run မှာ ဖြစ်ပါတယ်။ အဲဒီကနေ တစ်ဆင့် view နဲ့ display ကို အလုပ်လုပ်ခိုင်းမှာ ဖြစ်ပါတယ်။ classes ဆိုတဲ့ folder ထဲမှာ guestbook.php ဆိုတဲ့ class ကို ထည့်ထားပါတယ်။ simpletest folder ကတော့ simpletest ရဲ့ Folder ဆိုပါတော့။

အဆင့် (၂) စစ်ဆေးမှုအတွက် ပြင်ဆင်ခြင်း

ဒီအဆင့်ကတော့ TDD အတွက် အရေးအကြီးဆုံး အဆင့်လို့ ဆိုနိုင်ပါတယ်။ ဒီအဆင့်မှာကတည်းက စစ်ဆေးခြင်းတွေကို လုပ်ရမှာ ဖြစ်ပါတယ်။ စစ်ပြီဆိုမှဖြင့် ဘာစစ်ရမှန်း မသိလို့တော့ မရပါဘူး။ ဘာတွေ ထည့်ရမယ်၊ ဘာတွေ ထွက်လာရမယ် ဘယ်လို အမှားတွေ ရှိနိုင်တယ် စသည်ဖြင့် အကုန်သိထားဖို့ လိုပါတယ်။ Function တွေက ဘာတွေ လုပ်ပေးရမယ်၊ ဖြစ်နိုင်ချေရှိတဲ့ Inputs တွေက ဘာတွေလဲ၊ အဲဒါတွေ ထည့်လိုက်ရင် သူနဲ့ သက်ဆိုင်တဲ့ Outputs တွေက ဘာတွေလဲ စသည်ဖြင့် အသေအချာ သိထားဖို့ လိုမှာ ဖြစ်ပါတယ်။

အဲဒီအပြင် Program ရဲ့ အားသာချက်တွေက ဘာတွေလဲ၊ အားနည်းချက်တွေက ဘာတွေလဲ၊ Program ရဲ့ အကြောင်းကို အသေးစိတ်ကအစ သိထားရပါမယ်။ ဒါကလဲ အပြင်မှာ QC စစ်တဲ့သူတွေလိုပါပဲ။ ဘယ်လို စစ်ရမယ်ဆိုတာ ဘာတွေလုပ်ပေးနိုင်လဲ၊ ဘာတွေရလာမှာလဲ၊ ဘယ်လိုလုပ်သွားတာလဲ အကုန်သိမှ စစ်လို့ရတာပါ။

အဲဒီတော့ ကျွန်တော်တို့ရေးမယ့် GuestBook အတွက် စစ်ကြည့်ရအောင် အစိတ်အပိုင်းကလည်း တစ်ပိုင်း တည်း၊ Reading အပိုင်းပဲ။

  • function မှာ ဘာ inputs မှာ မရှိဘူး။ Database ထဲမှာ ရှိတဲ့ အချက်အလက်တွေကို ယူပေးရမယ်။ ပြီးရင် Screen မှာ ပြပေးနိုင်ရမယ်။
  • Guestbook Array Record တစ်ခုကို ဖော်ထုတ်ပေးနိုင်ရမယ်။ name ပါမယ်။ message ပါမယ်။ အကယ်၍ အထဲမှာ record တစ်ခုမှ မရှိဘူးဆိုရင် empty array တစ်ခု ထုတ်ပြနိုင်ရမယ်။
  • အကယ်၍ အထဲမှာ records တွေရှိတယ်ဆိုရင် array မှာ တစ်ခု သို့မဟုတ် တစ်ခုထက်ပိုတဲ့ Record တွေ ရှိနေရမယ်။
  • အဲဒီအပြင် Array မှာ တိကျတဲ့ ပုံစံရှိရမယ်။ အောက်မှာ ပြထားတဲ့ ပုံစံတူမျိုးပေါ့ …
Array (
	[0] => Array (
		['name'] = "mm"
		['message'] = "Hello, there."
	[1] => Array (
		['name'] = "nn"
		['message'] = "Hi, there."
	)
)

အဆင့် (၃) Test တစ်ခု ရေးသားခြင်း

ကဲ ဒီတစ်ခါတော့ TDD Test တစ်ခု အမှန်အကန် ရေးသားပါပြီ။ guestbook_test.php လို့ အမည် ပေးထားပါတယ်။ test folder ထဲမှာ ဖြစ်ရပါမယ်။

ကဲ စစ်တဲ့ Program တစ်ခု စရေးကြည့်ရအောင်

<?php
    require_once(dirname(__FILE__) . '/simpletest/autorun.php');
    require_once('../classes/guestbook.php');

    class TestGuestbook extends UnitTestCase {
        function testViewGuestbookWithEntries()
        {
            $guestbook = new GuestBook();
            // Add new records first
            $guestbook -> add("mm", "Hello, there.");
            $guestbook -> add("nn", "Hi, there.");
            $entries = $guestbook -> viewAll();

            $count_is_greater_than_zero = (count($entries) > 0);
            $this->assertTrue($count_is_greater_than_zero);
            $this->assertIsA($entries, 'array');
            foreach($entries as $entry) {
                $this->assertIsA($entry, 'array');
                $this->assertTrue(isset($entry['name']));
                $this->assertTrue(isset($entry['message']));
            }
        }

        function testViewGuestbookWithNoEntries()
        {
            $guestbook = new Guestbook();
            $guestbook->deleteAll(); // Delete all the entries first so we know it's an empty
            $entries = $guestbook->viewAll();
            $this -> assertEqual($entries, array());
        }
    }
    ?>

စစ်တဲ့ Program သာ စရေးထားပေမယ့် တကယ်တန်းတော့ Code တစ်ခုမှာ မရေးရသေးပါဘူး။ Assertion ဆိုတာတွေက မှန်လား မှားလား စစ်တာတွေပါ။ assertTrue() ဆိုရင် မှန်လား၊ Condition နဲ့ ကိုက်လားပေါ့။ $count_is_greater_than_zero ကို assertTrue() ဆိုတော့ အဲဒီ condition မှန်လားပေါ့။

အခု စစ်လိုက်တဲ့ Program မှာ entries နဲ့လား၊ entries မပါဘူးလားဆိုပြီး နှစ်ခု စစ်ထားတာ တွေ့ရပါလိမ့်မယ်။ အဲဒီလို အခြေအနေ နှစ်ခုလုံးကို စစ်ပေးပါတယ်။ အဲဒီ အခြေအနေ နှစ်ခုကို Pass ဖြစ်လား မဖြစ်ဘူးလား။ မဖြစ်သေးသ၍ ကိုယ့်ရဲ့ Code က အလုပ် မဖြစ်သေးပါဘူး။ အဲဒီအပြင် သတိထားဖို့ လိုတဲ့ တစ်ချက်က function တွေကို နာမည်ပေးတဲ့ နေရာမှာ test ဆိုတာနဲ့ စပြီး ပေးပါတယ်။ ဘာကြောင့် အဲဒီလို ပေးရသလဲဆိုရင် အဲဒီနာမည်နဲ့ စတာတွေကို SimpleTest က သုံးတဲ့အတွက်ပါ။ ဒါကြောင့် စစ်စေချင်တဲ့ Run စေချင်တဲ့ function တွေ class တွေကို test နဲ့ စပေးဖို့လိုမှာ ဖြစ်ပါတယ်။

အဲဒီအပြင် ရေးထားတဲ့ Test Code မှာ အခြား assertion method တွေလည်း သုံးထားပါသေးတယ်။ assertTrue, assertIsA နဲ့ assertEquals စသည်ဖြင့်ပေါ့။ assertTrue က တန်ဖိုးမှန်လား၊ မမှန်လား စစ်ပေးပါတယ်။ AssertIsA က varible အနေနဲ့ တိကျတဲ့ Type မှန်ရဲ့လား၊ တိကျတဲ့ class ဟုတ်ရဲ့လားဆိုတာ စစ်တာပါ။ assertEquals ဆိုတာတော့ တန်ဖိုးတစ်ခုနဲ့ အပြည့်အဝ တူရဲ့လားဆိုတာကို စစ်တာပါ။

အောက်မှာ ပြထားတာတွေကတော့ SimpleTest မှာ သုံးတဲ့ assertion methods တွေပါ

assertTrue($x) Fail if $x is false
assertFalse($x) Fail if $x is true
assertNull($x) Fail if $x is set
assertNotNull($x) Fail if $x not set
assertIsA($x, $t) Fail if $x is not the class or type $t
assertNotA($x, $t) Fail if $x is of the class or type $t
assertEqual($x, $y) Fail if $x == $y is false
assertNotEqual($x, $y) Fail if $x == $y is true
assertWithinMargin($x, $y, $m) Fail if abs($x – $y) < $m is false
assertOutsideMargin($x, $y, $m) Fail if abs($x – $y) < $m is true
assertIdentical($x, $y) Fail if $x == $y is false or a type mismatch
assertNotIdentical($x, $y) Fail if $x == $y is true and types match
assertReference($x, $y) Fail unless $x and $y are the same variable
assertClone($x, $y) Fail unless $x and $y are identical copies
assertPattern($p, $x) Fail unless the regex $p matches $x
assertNoPattern($p, $x) Fail if the regex $p matches $x
expectError($x) Swallows any upcoming matching error
assert($e) Fail on failed expectation object $e

အသေးစိတ် သိချင်တယ်ဆိုရင်​တေ့ ဒီနေရာမှာ သွားကြည့်နိုင်ပါတယ်။

အဆင့် (၄) စတင် စစ်ဆေးခြင်း

စစ်ဆေးဖို့အတွက် Code တွေ တော့ ရေပြီးသွားပြီ။ guestbook.php လည်း မရေးရသေး၊ ဘာမှကို မရေးရသေးတဲ့အချိန်မှာ failed test တစ်ခုနဲ့ စမှာ ဖြစ်ပါတယ်။ အဲဒီလို စစ်ဖို့အတွက်ကလည်း လွယ်ပါတယ်။ guestbook_test.php ဆိုတဲ့ ဖိုင်ကို ခေါ်ကြည့်ရုံပါပဲ။

အဲဒီလို ပြတာ ဘာကြောင့်လဲ။ လွယ်ပါတယ်။ guestbook.php ဆိုတဲ့ Class မှ မဆောက်ရသေးတာကိုး။ ဒီတော့ Fail ဖြစ်ပီပေါ့။ ကဲ ပထမဦးဆုံး warning အရ guestbook.php ကို အရင်ဆောက်လိုက်ရအောင် ဘယ်အထဲမှာလဲဆို​တော့ classes ဆိုတဲ့ Folder ထဲမှာပါ။

<?php
class GuestBook
{
		public function viewAll() {

		}

		public function add ($name, $message) {

		}

		public function deleteAll() {

		}
}

ဒီတစ်ခါ guestbook_test.php ကို ပြန် Run ကြည့်ပါမယ်။ ဒီတစ်ခါတော့ အရင်တစ်ခုနဲ့ မတူ​တော့ပါဘူး။ နည်းနည်း တိုးတက်လာပါပြီ။

ဒီတစ်ခါမှာတော့ test code ရဲ့ အနှစ်သာရ ပြည့်ဝလာပါပြီ။ တကယ့်ကို စစ်ပေးနိုင်တဲ့ အခြေအနေ ရောက်လာပါပြီ။ ရှေ့ဆက်ပြီး Code ဆက်ရေးကြည့်လိုက် စစ်လိုက်လုပ်ကြည့်ရ​အောင်

အဆင့် (၅) ရေးရင်း စစ်၊ စစ်ရင်း ​ရေ

ကဲ ရှေ့ဆက်ပြီး guestbook.php ကို ဆက်လက်ရေးပါ့မယ်။

<?php
class Guestbook
{
	// To save time, instead of creating and connecting to a database, we're going to
	// simulate a "database" by creating a static entries array here.
	// It will be like we have two entries in the table.

	private static $_entries = array(
		array (
			'name' => 'Kirk',
			'message' => 'Hi, I\'m Kirk.'
		),
		array (
			'name' => 'Ted',
			'message' => 'Hi, I\'m Ted.'
		)
	);

	public function viewAll() {
		// Here, we should retrieve all the records from the database.
		// This is simulated by returning the $_entries array
		return self::$_entries;
	}

	public function add( $name, $message ) {
		// Here, we simulate insertion into the database by adding a new record into the $_entries array
		// This is the correct way to do it: self::$_entries[] = array('name' => $name, 'message' => $message );
		self::$_entries[] = array('notname' => $name, 'notmessage' => $message ); //oops, there's a bug here somewhere
		return true;
	}

	public function deleteAll() {
		// We just set the $_entries array to simulate
		self::$_entries = array();
		return true;
	}
}

အမှားတွေကို တမင်သက်သက် ထားကြည့်ပါမယ်။ ထပ်စစ်ကြည့်ရအောင်

ဘာကြောင့် အဲဒီအမှားတွေ ပြနေရသလဲဆိုရင် ကျွန်တော်တို့ ရေးထားတဲ့ guestbook_test.php မှာ name, message ဆိုတဲ့ variable နှစ်ခုကို အောက်မှာ ပြထားတဲ့အတိုင်း စစ်ထားတာကြောင့်ပါ။

ကဲ ဒီတစ်ခါတော့ တမင်မှား​အောင် လုပ်ထားတာတွေ ပြန်ပြင်လိုက်ရအောင်

<?php
class Guestbook
{
	// To save time, instead of creating and connecting to a database, we're going to
	// simulate a "database" by creating a static entries array here.
	// It will be like we have two entries in the table.

	private static $_entries = array(
		array (
			'name' => 'Kirk',
			'message' => 'Hi, I\'m Kirk.'
		),
		array (
			'name' => 'Ted',
			'message' => 'Hi, I\'m Ted.'
		)
	);

	public function viewAll() {
		// Here, we should retrieve all the records from the database.
		// This is simulated by returning the $_entries array
		return self::$_entries;
	}

	public function add( $name, $message ) {
		// Here, we simulate insertion into the database by adding a new record into the $_entries array
		// This is the correct way to do it: self::$_entries[] = array('name' => $name, 'message' => $message );
		self::$_entries[] = array('name' => $name, 'message' => $message ); //fixed
		return true;
	}

	public function deleteAll() {
		// We just set the $_entries array to simulate
		self::$_entries = array();
		return true;
	}
}

ကဲ ဒီတစ်ခါ​တော့ စိတ်ချမ်းသာစရာ ​ကောင်းသွားပြီ ထင်ပါတယ်။

မီးပွိုင့်က မီးစိမ်းပြလိုက်သလိုပါပဲ။ ကိုယ့် Code တော့ အလုပ်ဖြစ်ပြီလို့ ထအော်နိုင်ပါတယ်။

အဆင့် (၆) Refactor and Refine (ပြန်စစ်၊ ပြန်အချောသပ်)

ဒီအပိုင်းကတော့ အီတလီခေါက်ဆွဲတွေကို တပင်ခြင်း ရှင်းရတဲ့အပိုင်း ဖြစ်ပါတယ်။ မဆိုင်တဲ့ နာမည်တွေ ပေးထားမိရင် ပြန်ပြောင်း၊ ပြန် ပေါင်းသင့်တာကို ပြန်ပေါင်း၊ မှီခိုနေတာတွေကို ခွဲထုတ် စသည်ဖြင့် အများကြီး လုပ်ပေးဖို့လိုပါတယ်။ အဲဒီလို ရှင်းလင်းရေး၊ သန့်ရှင်းရေး လုပ်နေတဲ့ အချိန်မှာလဲ Test ကို Run ကြည့်နေဖို့လိုပါတယ်။ အဲဒီလို Run တိုင်း မီးစိမ်းပြနေတယ်ဆိုရင် အဆင်ပြေနေတယ်လို့ သိနိုင်ပါတယ်။

အဆင့် (၇) ပြန်ကျော့ခြင်း

ဒါကတော့ program မှာ function အသစ်တစ်ခု လိုလာတာနဲ့ Test တစ်ခု လိုလာပါတယ်။ အဲဒီအတွက် Test တစ်ခု ရေးလိုက် function တစ်ခု ဒါမှမဟုတ် class တစ်ခု တည်ဆောက်လိုက်လုပ်ရတဲ့ အထပ်ထပ်ကျော့ပြီး လုပ်ရမယ့်အပိုင်းပါ။ စစ်တာ အရင်ရေး ပြီးရင် code ရေး၊ စစ်ကြည့် fail ဖြစ်နေရင် ဆက်ရေး၊ နောက်ဆုံး အောင်သွားပြီဆိုရင် Refactoring လုပ်စသည်ဖြင့် Program မပြီးမဆုံးမခြင်း လုပ်ရမယ့် အပိုင်းပါ။

နိဂုံး

နောက်ဆုံး အ​နေနဲ့ ပြောရမယ်ဆိုရင် ကိုရဲ​နောင်ရဲ့ ပြောစကားနဲ့ပဲ အဆုံးသတ်ရပါမယ်။ Test-Driven Development ဆိုတာ လုံခြုံမှု အပေးနိုင်ဆုံး Development Process ဆိုပေမယ့် အပြောလွယ်သလောက် အလုပ်ခက်ပါတယ်တဲ့။ အစပိုင်းမှာ အလုပ်နှစ်ခု ပိုလာပေမယ့် နောက်တစ်ချိန် Bug ပင်လယ်ထဲမှာ နစ်ပြီး သေမယ့် ဘေးကနေ ဝေးစေပါတယ်။ Programmer တွေအတွက် အလေ့အထ ကောင်းတစ်ခု ဖြစ်ပြီး Program ကို ပိုပြီး တိတိကျကျ နားလည်စေပါတယ်။ System Analyst အတွက်လည်း အလုပ်တွေ ပိုပြီး အဆင်ပြေစေမယ်လို့ ကျွန်တော် ထင်ပါတယ်။ အခုလို Test-Driven Development အကြောင်းကို မျက်စိဖွင့်ပေးခဲ့တဲ့ ဆရာ ကိုရန်နောင်ကို ကျေးဇူးအများကြီး တင်ပါတယ်လို့ ပြောပါရစေ။ ကျွန်တော့်အနေနဲ့လည်း လက်ဆင့်ကမ်းဖို့ တာဝန်ရှိတာနဲ့ အညီ လက်ဆင့်ကမ်းပေးလိုက်ရပါတယ်။ အမှားအယွင်း အတိမ်းအ​စောင်းရှိပါက ထောက်ပြပေးနိုင်ပါတယ်ခင်ဗျာ။

အားလုံးပဲ ရွှင်လန်းချမ်းမြေ့ပါစေ …

Facebook comments:

7 Responses

  1. Ei Maung says:

    Here is the another explaination on TDD – http://bit.ly/h6xsur

  2. myintkt says:

    Very nice!

  3. ahkeno says:

    Thank Ko Ei Maung for invitation,also Thank Ko Thia for sharing!!

  4. mgyin says:

    I think testing development will be popular at later. how?

  5. mgyin says:

    function CalculateScore()
    {
    $data = getScore();
    $result = (($data[0]+$data[1]+…..)/$data.length)+1;
    return $result;
    }
    function getScore()
    {
    $db_data[] = // get from database; it will return score array
    //example – ( “20″,”80″,”30″,”…) don’t know length
    return $db_data;
    }

    I can test second function. But i am confuse to test first function that CalculateScore().
    How can i test the first function?

    I wrote to test first function we will call getScore() or write select statement to get Score and then sum the score that got from database divide with score length and sum with 1.

    I think
    “the process of test function = the process of CalculateScore()”

    Is it same with the process with CalculateScore()? So the test result will be always true.

    Please share me.

  6. 4tee says:

    I am currently doing cppUnit Testing for C++ program. I found it good only some case when there is logical return.

    But it become not useful when i need to do some operations that doesn’t return any value.

    If the function require the user input during execution, then it is also become useless.

    Good thing that i like about TDD is that i can ensure every logical steps before i continue with next module. Bad thing is TDD still rely on human logical thinking about possible error scenarios and it is easily missed.

  7. ကျေးဇူး အထူးတင်ပါတယ်ဗျာ။ ဒါနဲ့ .NET မှာရော အဲဒါ ဘယ်လို လုပ်မလဲ ခင်ဗျ

Leave a comment


*