برای صحبت دربارهی تست یکپارچگی، ابتدا لازم است بدانیم منظور ما از یکپارچگی چه چیزی است. مفهومی یکپارچگی (integrity) در سیستمهای کامپیوتری این است که بدانیم آیا هر بخشی از سیستم (که از قبل مطمئنیم خوب و درست کار میکند) میتواند در تعامل با سایر بخشها هم درست کار کند؟ آیا در هنگام دریافت ورودی از بخشهای دیگر، زبان آنها را میفهمد؟! یا زمانیکه میخواهد خروجی تولید کند؛ این خروجی را به طوری تولید میکند که برای ماژولهای دیگر نیز قابل فهم و قابل استفاده باشد یا نه؟! آیا عملکرد یک ماژول میتواند تاثیر مخربی برای بقیهی ماژولها داشته باشد؟ فرآیندهای تست یکپارچگی به ما کمک میکنند تا به این سوال و چندین سوال دیگر پاسخ بدهیم
شاید در نگاه اول و از دید فردی که در حوزهی نرمافزارهای Enterprise تجربهای نداشته است، اگر هرکدام از ماژولها یا بخشهای نرمافزار، به تنهایی خوب و درست کار کنند؛ قاعدتا در صورتیکه وارد سیستم شوند و با ماژولهای دیگر در رابطه باشند هم درست کار میکنند و مشکلی پیش نخواهد آمد. اما در واقعیت اینطور نیست! بلکه وصل کردن ماژولهای مختلف یک سیستم نرمافزاری به یکدیگر، به خودیِ خود یکی از پرچالشترین مسائل در طراحی نرمافزار است. در این بخش به بررسی مشکلاتی که ممکن است رخ دهد، می پردازیم:
1- عدم تطابق خروجی یک ماژول نرمافزاری با ورودی ماژول بعدی
در سیستمهای نرمافزاری، دادهها در بین بخشها و ماژولهای مختلف در جریان اند و به صورت مداوم از یک ماژول خارج و به ماژول دیگر وارد میشوند. در حین این گردش اطلاعات، ممکن است دادهای که از اینترفیس ورودی وارد ماژول می شود، گم شود یا اینکه جوری تغییر کند که در جریانِ دادهی برنامه انتظار آن را نداشتهایم. در اینصورت، استفاده از این داده، عملا برای ماژول های بعدی ناممکن می شود. (مثلا در یک کلاس، انتظار داشتهایم که یک عدد را بهعنوان تعداد محصولات دریافت کنیم تا محاسبات مورد نیاز را روی آن انجام دهیم؛ اما ورودی ارسال شده به این کلاس، از نوع String یا یک عدد منفی باشد. در اینصورت، طبیعتا این کلاس نمیتواند محاسبات مورد انتظار را انجام دهد چون تعداد محصولات، به درستی به او گزارش نشدهاست.)
2- تاثیر مخرب یک بخش بر روی بخش دیگر
یک بخش از برنامه ممکن است وقتی به تنهایی کار میکند، هیچ مشکلی ایجاد نکند؛ اما در هنگام اضافه شدن به سیستم، به طور ناخواسته، یک تاثیر مخرب روی ماژولهای دیگر داشته باشد و کار آنها را مختل کند. در نتیجه عملکرد یک ماژول نرمافزاری، علاوه بر ویژگیها و ساختار خود ماژول، به عملکرد ماژولهای دیگر نیز بستگی دارد و ماژولهای متفاوت می توانند از یکدیگر تاثیر مخرب بگیرند.
3- نتیجهی کلی کار بخشهای مختلف، چیزی نباشد که ما انتظار داریم
هر کدام از بخشهای کوچکتر سیستم، طبیعتا با توجه به تعریفی که دارند برای انجام یک عملیات کوچک طراحی شده اند. ما توقع داریم بعد از کنارهم گذاشتن این بخشهای کوچک، بتوانیم یک کار بزرگ را انجام دهیم و پس از انجام آن، نتیجه ی درستی بگیریم. اما زمانیکه این بخش ها با هم شروع به همکاری میکنند، ممکن است نتوانند با کمک یکدیگر آن کاربرد کلیای که ما از نتیجهی کار آنها انتظار داریم را تولید کنند. در اینصورت باید معماری نرمافزار و روابط بین بخشها بازنگری شوند تا خروجی همکاری این کلاسها، مطابق چیزی که انتظار داریم تکمیل شود.
4- اگر مشکل کوچکی در یک ماژول وجود داشته باشد، با بزرگتر شدن سطح برنامه، مشکل هم بزرگتر میشود
فرض کنید درون یک ماژول نرمافزاری، یک مشکل کوچکی جا مانده باشد که در مرحلهی Unit Test پیدا و رفع نشده است . طبیعتا با توجه به اینکه اندازه و پیچیدگی این ماژول جزئی،در مقایسه با کل سیستم کوچکتر و ساده تر است، خطایابی و رفع خطا نیز آسانتر از زمانی است که این ماژول بهعنوان جزئی از یک سیستم در نظر گرفته شدهاست. علاوه بر سادگی، ممکن است این مشکل وقتی وارد ماژول های بزرگتر برنامه می شود، بزرگتر و جدیتر هم بشود و روند برنامه را دچار مشکل کند! در صورتیکه شاید زمانیکه هنوز به سیستم اضافه نشدهبود، همچنین اثر مخربی روی روند اجرای کار ماژول نداشت.
5- متغیرهای global به دلیل اینکه حوزهی تعریفشان بزرگ است، بیشتر ممکن است دچار مشکل شوند
متغیرهایی که به صورت global تعریف می شوند، بخاطر سطح دسترسیای که از تمام بخشهای کلاس دارند، بیشتر ممکن است دچار چالش شوند. برای مثال ممکن است مقدار آنها درون هر تابع به صورت جداگانه تغییر کند. طبیعیاست که اگر تحت شرایطی، یکی از توابع مقدار این متغیر را طوری تغییر دهد که در جریان برنامه تعریف نشده است، مقدار آن غیر معتبر میشود و میتواند کل برنامه را دچار مشکل کند.
6- و خیلی مشکلات دیگر که می تواند در هنگام ترکیب کردن ماژولهای کوچکتر رخ بدهد که تعداد آنها میتواند به اندازهی تمام سیستمهای نرمافزاری دنیا و تمام دفعاتی که قرار است یک ماژول جدید به هرکدام از آنها اضافه شود، باشد...
برای تست یکپارچگی سیستم نرمافزاری، دو رویکرد کلی وجود دارد. یکی اینکه تمام ماژولهای کوچکتر را در یک مرحله و بدون هیچ ترتیب خاصی با هم ترکیب کنیم و بعد شروع به بررسی مشکلات پیش آمده و رفع خطاهای موجود بکنیم. به این روش، روش بیگ بنگ می گویند زیرا در این روش، درست مثل واقعه ی بیگ بنگ، یکدفعه همه ی اجزای جهانِ سیستم نرمافزاری ما، باهم ترکیب میشوند و سپس خطاها و مشکلات موجود در سیستم رفع میشود. خب همانطور که احتمالا حدس میزنید؛ این روش، اصلا روش خوبی نیست. چون در این رویکرد، پیدا کردن عامل خطاها و تفکیک خطاهای مربوط به ماژولهای مختلف بسیار سخت شده و متعاقبا رفع آن خطاها نیز به مراتب سختتر می شود.
در مقابل روش بیگ بنگ، یک رویکرد دیگر نیز برای تست یکپارچگی (Integration test) وجود دارد که در طی آن، تکتک ماژولها را جداگانه تست کرده و از درستبودن آنها مطمئن میشویم. سپس طبق استراتژی انتخاب شده، یک ترتیب خاص برای تست یکپارچگی انتخاب می کنیم و در هرمرحله، تعدادی از ماژولها را باهم ترکیب می کنیم تا زمانیکه کل سیستم آزمایش شود. ترتیب ترکیب این ماژولها، میتواند بهصورتهای زیر باشد:
1- یکپارچگی از بالا به پایین (Top-Down Integration)
در این روش، همانطور که از نام آن پیداست، ابتدا از ماژولهای سطح بالاتر و کلیتر شروع می کنیم و ارتباطات و اینترفیس های آنان را تست می کنیم. سپس در هر مرحله، طی الگوریتمی به ماژول های سطح پایینتر میرویم و انقدر این مراحل را طی میکنیم که کل سیستم از نظر یکپارچگی بین کامپوننت ها تست شده باشد.
2- یکپارچگی از پایین به بالا (Bottom-Up Integration)
در این روش، همانطور که از نام آن پیداست، عملیات تست کردن از کوچکترین ماژولها که در پایینترین سطوح دیاگرام ساختار برنامه هستند شروع می شود و در هرمرحله، با ادغامکردن کامپوننتهای مختلف، برگ های نمودار را حذف کرده و نتیجه ی ادغام آنها را به عنوان برگهای کامپوننتهای بالاتر در نظر میگیرد تا با آنها ترکیب شوند و یکپارچگی سیستم مورد آزمایش قرار بگیرد.
3- یکپارچگی مداوم (Continuous Integration)
در این روش، عملیات ادغام کامپوننت ها و تست آنها، تنها یکبار در انتهای توسعهی نرمافزار انجام نمیشود! بلکه هر روز یا هر چند روز یکبار، تست یکپارچگی انجام می شود. این روش، برای گروههایی که مبنای فعالیتشان مدل توسعه ی چابک است؛ بسیار مفید می باشد. چراکه این گروهها باید هر چند وقت یکبار (که این زمان براساس سیاست کاری هر گروه می تواند متغیر باشد اما به هرحال معمولا زمان خیلی زیادی نیست) یک خروجی قابل انتشار از نرمافزار خود ارائه دهند و قاعدتا قبل از انتشار، باید تمام تستهای لازم را روی آن انجام داده باشند و از پایدار بودن و قابل اطمینان بودن محصولی که منتشر کرده اند، مطمئن باشند
Source : Roger S. Pressman, Bruce R. Maxim. "Software Engineering A Practtitioner's Approach" - 9th Edition
امیدوارم این سری از مقالات برایشما مفید بوده باشد.
ممنون از همراهی شما