مان‌طور كه مي‌دانيد Unit Testing به معناي تست كردن قسمت كوچكي از برنامه است كه ماجول يا يونيت برنامه نام دارد و مي‌تواند در پيدا كردن اشكالات برنامه بسيار مؤثر واقع شود، اما در حقيقت نوشتن يك Unit Test بيشتر عملي است كه در قسمت طراحي نرم‌افزار به كار مي‌رود تا در قسمت Verification يا اشكال‌يابي، و مي‌تواند نظرات كاربران را بگيرد. به اين معنا كه وقتي كاربري در مورد سيستم نظر داد كه مشكلي در Unit وجود دارد و آن مشكل در Unit Testing حل شد، در قسمت‌هاي بعدي نمي‌توان از او براي آن قسمت از برنامه نظرخواهي كرد. علاوه بر آن، عملكرد صحيح تمام Unit Testها نمي‌تواند بدين معنا باشد كه همه سيستم خوب كار مي‌كند؛ زيرا ممكن است در ارتباط اجزاي سيستم مشكلي پيش آمده باشد.

Test Driven Development
تصور كنيد كه تست‌هاي نرم‌افزار خود را قبل از نوشتن برنامه آماده كنيد. اين كاري است كه ما درAgile Development انجام مي‌دهيم. در اين روش تست‌ها خودشان به وجود ميآيند و ما مي‌توانيم بگوييم كه رويه‌اي از سيستم را نمي‌نويسيم تا وقتي كه تستي از برنامه موفق نباشد و نشان دهد كه آن رويه لازم است. بدين معني كه مثلاً اول يك قطعه كد براي افزودن دانشجويي جديد به فهرست دانشجويان مي‌نويسيم، ولي چون در آن كد قطعه‌اي از كد كلاسي كه insert را انجام مي دهد وجود ندارد، برنامه اشكال مي گيرد. حال كار گروه اكس‌پي اين است كه برنامه را طوري درست كنند كه اين تست پاس شود و به قدري روي برنامه كار ‌كنند تا برنامه دلخواه به دست آيد.

با اين كار فكر مي‌كنيد چه فايده‌اي نصيب ما خواهد شد؟ مهم‌ترين فايده اين كار اين خواهد بود كه براي هر رويه ياFunction، يك تست داريم كه عملكرد آن را تأييد مي‌كند. تصور كنيد كه قرار است رويه و عملكرد جديدي را در سيستم اعمال كنيم. اگر براي آن رويه تستي بنويسيم و آن تست را انجام دهيم، مشاهده مي‌كنيم كه تأثيري روي كل برنامه خواهد گذاشت يا خير؟ و ترس ما را از اعمال تغييرات در سورس كد برنامه از بين مي‌برد.
به علا‌وه، چنين كاري باعث خواهد شد برنامه‌اي را كه مي‌خواهيم بنويسيم، هم به اينترفيس آن اهميت دهيم هم به عملكرد صحيح آن و رابطه رويه‌هاي آن با هم.

يكي از مهم‌ترين مزاياي اين روش اين است كه برنامه ما آزمون‌پذير يا Testable است. از ديگر مزاياي نوشتن تست قبل از نوشتن برنامه اين است كه مي‌توانيم مستندات خود را از روي اين تست‌ها داشته باشيم. مثلاً اگر مي‌خواهيد بدانيد كه يك Object چگونه فراخواني مي‌شود و چه پارامترهايي بايد به آن فرستاد، كافي است به تست آن كلاس نگاهي بيندازيم. اين مستندات هميشه بروزند و حتي قابل اجرا نيز هستند.

شكل 1 دياگرام UML قسمتي از سيستم حقوق دستمزد را نشان مي‌دهد. كلاس payroll از كلاسEmployeeDatabase براي گرفتن objectهاي كارمندان يا Employee استفاده مي‌كند. در حقيقت اين كلاس از كلاسEmployee درخواست مي‌كند كه حقوق كارمند را حساب كند. سپس اين حقوق را به شيء CheckWriter جهت چاپ چك كارمند ارسال مي‌كند. در آخر نيز اين پرداخت را به كلاس Employee جهت پست كردن چك ارسال مي‌كند و object مربوطه را به ديتابيس پاس مي‌دهد.

شکل 1
تصور كنيد كه تا به حال هيچ كدي براي اين سيستم ننوشته‌ايم و اين دياگرام تنها چيزي است كه ما در جلسه اوليه شناخت سيستم داريم. اولين قدم براي ايجاد چنين سيستمي، نوشتن تست‌هايي است كه عملكرد شيءpayroll را مشخص كند. ممكن است از خود سؤال كنيد: ما كه هنوز نمي‌دانيم از چه پايگاه اطلاعاتي استفاده مي‌كنيم. آيا مي‌خواهيم در سيستم خود از Sql Server استفاده كنيم يا از اوراكل؟ شايد هم سؤال كنيد كه چگونه مي‌توانيم بفهميم كه چك كارمندي واقعاً چاپ شده است يا خير؟

شکل 2
چون اطلاعاتي كه در دست داريم كم است، مي‌توانيم از Mock Object يا شيء ظاهري استفاده كنيم. راه حل اين است كه از اينترفيس استفاده نماييم. براي اين كار مي‌توانيم همان‌طور كه در شكل 2 مشاهده مي‌كنيد، اينترفيس‌هايي بين كلاس‌هاي مرتبط در سيستم payroll قرار دهيم و تست مربوط به اين اينترفيس‌ها را بنويسيم. هم‌اكنون از اينترفيس‌هاي EmployeeDatabase و CheckWriter و Employee جهت برقراري ارتباط بين شيء‌ها استفاده مي‌شود. اضافه بر اين، سه Mock Object هم ايجاد شده است كه با اينترفيس‌ها ارتباط برقرار مي‌كند. اينMock Objectها توسط شيء payrollTest مورد جست‌وجو قرار مي‌گيرند تا صحت كار شيء payroll را تضمين كنند.
تست زير مي‌تواند براي اين كار مورد استفاده قرار گيرد:

()Public void testPayRoll
{
;()MockEmplyeeDatabase db=new MockEmplyeeDatabase
;()MockCheckWriter w=new MockcheckWriter
;(Payroll p=new Payroll(db,w
;()p.payEmployees
;(()assert(W.checksWereWrittenCorrectly
;(()assert(db.paymentsWerePostedCorrectly
}


همان‌طور كه در اين كدها مشاهده مي‌كنيد، شيء‌هاي Mock به وجود ميآيند و آن‌ها را به شيء Payroll ارسال مي‌كنيم و به شيء payroll مي‌گوييم كه پرداخت به تمام كارمندان را انجام دهد. بعد از آن از شيء Mock در مورد صحت عمليات انجام شده سؤال خواهد شد. كاري كه اين تست انجام مي‌دهد، در حقيقت اين است كه چك كند كه شيء payroll رويه‌هاي صحيح و با اطلاعات صحيح را فراخوانده است يا خير. ولي اين بررسي نمي‌تواند تست كند كه آيا چك‌ها درست نوشته شده‌اند يا خير. به ‌علا‌وه، نمي‌تواند بررسي كند كه پايگاه اطلاعاتي بروزآوري شده است يا خير؟ كاري كه اين تست انجام مي‌دهد اين است كه كلاس ‌Payroll را به تنهايي چك كند.

Acceptance Test
Unitتست‌ها در حقيقت ابزاري ضروري براي تست كردن سيستم به شمار مي‌روند، ولي كارايي خوبي ندارند؛ زيرا نمي‌توانند صحت كارايي كل سيستم را تضمين نمايند. Unit Testها در واقع تست‌هاي جعبه سفيد (White box) هستند كه در آن تنها مكانيزمي خاص در سيستم چك مي‌گردد. براي اين‌كه بتوانيم نيازهاي كاربران سيستم خود را چك كنيم، به تست Black box يا Acceptance Test نياز داريم. اين تست‌ها نيازهاي كاربران را در قسمت‌هايي از برنامه چك مي‌كنند و ما را از اين‌كه نياز كاربران از سيستم بر آورده شده است يا خير، مطلع مي‌كنند. اين تست‌ها معمولاً توسط كساني نوشته مي‌شوند كه هيچ اطلاعاتي از مكانيزم سيستم و اجزاي داخلي آن ندارند و معمولاً توسط كاربران سيستم تهيه مي‌شوند Acceptance Testها برنامه‌هايي هستند كه حتي مي‌توان آن‌ها را اجرا نمود و اغلب با استفاده از Scripting Languageها نوشته مي‌شوند.

وقتي مشتري سيستم اين تست‌ها را نوشت، برنامه نويسان مي توانند براي اين‌كه از نياز كاربران آگاه شوند، آن تست‌ها را بخوانند. براي مثال، سيستم حقوق و دستمزد را در نظر بگيريد. در مرحله اول ما بايد بتوانيم كارمندي را به سيستم اضافه نماييم يا او را از ديتابيس حذف كنيم. به كدهاي زير كه قسمتي از اين تست هستند نگاه كنيد:

‌در اين تست ما كارمندي را با شماره 1256، نام Amin Safaei و حقوق دو ميليون در بانك اطلاعاتي وارد كرده‌ايم. سپس به سيستم مي‌گوييم وقت پرداخت است و بايد حقوق كارمند را پرداخت كنيم. سپس تست مي‌كنيم كه چك آن كارمند با مقداري كه وارد كرده‌ايم، چاپ شده است.

()Poblice void testPayRoll
}
MockEmplyeeDatabase db=new MockEmplyeeDataba
;()MockchekWriter w=new MockCheckWrit


همان‌طور كه مشاهده مي‌كنيد، نوشتن اين تست براي كارفرماي سيستم كار آساني است. اضافه كردن امكانات جديد به اين قطعه كد نيز كار سختي به نظر نمي‌رسد.

هر تست در واقع به سيستم وارد مي‌شود و نتيجه‌اي را در بر خواهد داشت. اين تست‌ها در مقابل اطلاعات ورودي تست خواهند شد و نتيجه اين تست‌ها با جوابي كه از سيستم انتظار داريم مقايسه خواهند شد. اگر جواب به دست آمده با جوابي كه انتظار داريم مساوي باشد، به اصطلاح تست پاس شده است. در غير اين صورت، اصلاحات مورد نظر تا به دست آمدن نتيجه مساوي، ادامه خواهد داشت.