دو سرویس میتوانند بهتنهایی کاملاً سالم باشند و کنار هم شکست بخورند: سرویس قیمت مبلغ را به تومان برمیگرداند، Checkout آن را ریال میخواند؛ تولیدکننده فیلد userId را تغییر میدهد، مصرفکننده هنوز customer_id میخواهد؛ درگاه Callback را دوبار میفرستد و سفارش دوبار ثبت میشود. اینها باگ یک تابع منفرد نیستند؛ باگِ مرز و همکاری هستند. تست یکپارچهسازی (Integration Testing) برای همین مرزهاست.
پاسخ کوتاه: تست یکپارچهسازی بررسی میکند دو یا چند مؤلفه یا سیستم، از طریق رابط واقعی یا نماینده، داده و کنترل را درست مبادله میکنند. هدف فقط گرفتن پاسخ ۲۰۰ نیست؛ باید قرارداد، mapping، state، تراکنش، خطا، timeout، retry، idempotency، ترتیب پیام، احراز هویت و سازگاری نسخه هم سنجیده شوند.
مرز مقاله: Component Integration تعامل اجزای داخل محصول را میسنجد؛ System Integration تعامل محصول با سامانههای بیرونی مانند درگاه، پیامک یا شریک تجاری را. هر دو زیر چتر Integration Testing هستند، ولی محیط، مالک و ریسک متفاوت دارند.
تست یکپارچهسازی چیست؟
Integration Testing سطحی از تست است که رابطها و تعاملات میان Test Objectها را بررسی میکند. این Test Objectها میتوانند کلاس و پایگاه داده، چند ماژول، دو سرویس، تولیدکننده و مصرفکننده پیام یا سیستم شما و API یک شریک باشند.
طبق ISTQB CTFL v4.0.1، Component Integration بر رابط و تعامل مؤلفهها تمرکز دارد و به استراتژیهایی مانند Bottom-Up، Top-Down یا Big Bang وابسته است؛ System Integration رابط سیستم تحت تست با سیستمها و سرویسهای بیرونی را هدف میگیرد. مقاله سطوح تست نرمافزار جای این دو سطح را در مدل پنجسطحی نشان میدهد.
هدف تست Integration چیست؟
- تایید قرارداد ورودی و خروجی رابط
- بررسی تبدیل و معنای داده میان اجزا
- تایید ترتیب فراخوانی و تغییر state
- آزمون تراکنش، rollback و سازگاری داده
- بررسی timeout، retry، fallback و circuit breaker
- کشف ناسازگاری نسخه و configuration
- تایید احراز هویت، مجوز و propagation هویت
- مشاهده trace، log و correlation در چند مؤلفه
تفاوت Unit، Integration و System Testing
| ویژگی | Unit/Component | Integration | System |
|---|---|---|---|
| Test Object | یک جزء در انزوا | مرز و همکاری چند جزء/سیستم | کل محصول یکپارچه |
| وابستگی | اغلب Test Double | یک یا چند وابستگی واقعی/نماینده | سامانه کامل در محیط نماینده |
| هدف شکست | منطق داخلی | قرارداد، داده، زمان و خطا | سفر و نیازمندی سیستم |
| سرعت معمول | بسیار سریع | متوسط | کندتر |
| مکانیابی علت | آسان | میان چند مرز | پیچیدهتر |
| نمونه | تابع سقف تخفیف | Pricing با Checkout | خرید کامل از UI تا سفارش |
هیچ خط سرعت قطعی وجود ندارد؛ یک Integration Test بد میتواند از UI Test هم کندتر شود. تمایز اصلی Test Object و هدف است. تستی که فقط Mockهای تعریفشده توسط همان تیم را صدا میزند، شاید عملاً Unit Test باشد—even اگر نام فایل آن integration باشد.
Component Integration و System Integration
Component Integration Testing
تعامل اجزای داخل مرز سیستم را میسنجد:
- Repository با پایگاه داده واقعی
- Controller با Service و serializer
- Checkout با Pricing و Inventory
- Publisher با broker و consumer داخلی
- Frontend با Backend تحت مالکیت همان محصول
این تستها معمولاً در کنترل تیماند، در CI قابلتکرارند و میتوانند با container یا محیط موقت اجرا شوند.
System Integration Testing
مرز سامانه با دنیای بیرون را میسنجد:
- درگاه پرداخت و settlement/Callback
- سرویس OTP یا پیامک
- سامانه حملونقل و رهگیری
- CRM، حسابداری یا ERP
- Identity Provider و SSO
- API شریک یا نهاد بیرونی
در این سطح، قرارداد فنی کافی نیست؛ محدودیت Sandbox، SLA، rate limit، certificate، timezone، سیاست retry و مسیر پشتیبانی نیز بخشی از ریسکاند. تغییر خارج از کنترل شماست و تست سازگاری نسخه و monitoring اهمیت بیشتری میگیرد.
تست یکپارچهسازی چه باگهایی پیدا میکند؟
| دسته نقص | نمونه | شاهد مناسب |
|---|---|---|
| قرارداد | فیلد required حذف یا type عوض شده است | schema diff و response |
| معنای داده | ریال در یک سرویس و تومان در سرویس دیگر | payload و رکورد ذخیرهشده |
| تراکنش | سفارش ثبت میشود ولی موجودی کم نمیشود | state چند datastore |
| زمان | timeout کوتاهتر از رفتار واقعی وابستگی است | trace و timestamp |
| تکرار | Callback دوباره باعث برداشت/ثبت تکراری میشود | idempotency key و رخدادها |
| ترتیب | رویداد «ارسال شد» پیش از «پرداخت شد» میرسد | offset و event timeline |
| امنیت | token یا role به سرویس بعدی درست منتقل نمیشود | claim و audit log ماسکشده |
| پیکربندی | آدرس، flag یا certificate محیط اشتباه است | deployment/config snapshot |
رویکردهای تست یکپارچهسازی
رویکرد افزایشی (Incremental)
اجزا مرحلهای متصل و بعد از هر اتصال آزموده میشوند. دامنه شکست کوچکتر، بازخورد زودتر و علتیابی سادهتر است. در معماریهای مدرن، این رویکرد اغلب با pipeline و محیطهای موقت ترکیب میشود.
Top-Down
از orchestration یا لایه بالاتر شروع میکنیم و وابستگیهای پایینِ آمادهنشده را با Stub جایگزین میکنیم. برای تایید زودهنگام جریان اصلی مفید است، ولی ممکن است Stubهای فراوان و غیرواقعی بسازد.
Bottom-Up
اجزای پایه مانند repository، adapter یا سرویس دامنه ابتدا با هم آزموده میشوند و Driver نقش فراخواننده بالاتر را میگیرد. زیرساخت و منطق پایین زودتر محکم میشود، اما workflow سطح بالا دیرتر دیده میشود.
Sandwich/Hybrid
Top-Down و Bottom-Up همزمان به لایه میانی نزدیک میشوند. برای تیمهای موازی مفید است، اما هماهنگی Test Doubleها و قرارداد نقطه ملاقات را پیچیده میکند.
Big Bang
بخشهای متعدد یکباره متصل میشوند. در نمونه بسیار کوچک ممکن است قابلقبول باشد، اما در سیستم بزرگ وقتی شکست رخ دهد هم رابطهای زیادی مظنوناند و هم خطا دیر کشف شده است. Big Bang را انتخاب پیشفرض نکنید؛ اگر ناچارید، observability، rollout مرحلهای و دامنه محدود ضروریاند.
انواع عملی Integration Test در معماری امروز
تست Repository و پایگاه داده
SQL، mapping، constraint، transaction، migration و رفتار driver با پایگاه داده واقعی یا نسخه سازگار آزمایش میشوند. دیتابیس in-memory همیشه رفتار index، collation، timezone، isolation و query planner تولید را بازنمایی نمیکند.
تست API و سرویس
status code، schema، header، validation، authentication، pagination، خطا و side effect بررسی میشوند. راهنمای مبانی تست API طراحی سناریو و لایههای API را تکمیل میکند.
Contract Testing
Consumer و Provider روی شکل و معنای تعامل توافق میکنند و ناسازگاری پیش از استقرار مشترک کشف میشود. Contract Test جای تست رفتار واقعی، شبکه یا امنیت را نمیگیرد؛ فقط یک مرز مشخص از سازگاری را سریعتر میسنجد.
تست صف و معماری Event-Driven
Schema پیام، delivery چندباره، ترتیب، partition key، retry، dead-letter queue و پردازش idempotent هدفاند. فقط مشاهده «پیام منتشر شد» کافی نیست؛ باید اثر consumer و حالت failure نیز دیده شود.
تست سرویس بیرونی
ترکیبی از Service Virtualization، Sandbox رسمی و تعداد محدودی تست end-to-end کنترلشده لازم است. برای درگاه ایرانی، مقاله تست درگاه پرداخت و Sandbox سناریوهای مالی را عمیقتر بررسی میکند.
Stub، Mock، Fake، Spy و Driver چه تفاوتی دارند؟
| Test Double | نقش | نمونه | خطر |
|---|---|---|---|
| Stub | پاسخ از پیش تعیینشده میدهد | OTP همیشه «ارسال شد» برگرداند | رفتار واقعی سادهسازی میشود |
| Mock | انتظار تعامل را تایید میکند | فراخوانی gateway با مبلغ مشخص | وابستگی به جزئیات پیادهسازی |
| Fake | پیادهسازی سبک ولی کاری | مخزن in-memory | تفاوت با semantics واقعی |
| Spy | فراخوانیها را ثبت میکند | تعداد eventهای منتشرشده | تمرکز بیشازحد بر call |
| Driver | جزء پایین را فراخوانی میکند | فراخواننده موقت adapter | workflow بالادست را کامل نشان نمیدهد |
هدف Test Double کنترل شرایط است، نه ساختن جهانی که همیشه مطابق انتظار تست عمل کند. هر قرارداد بحرانی باید در جایی با Provider واقعی، container سازگار یا Sandbox معتبر آزموده شود.
چکلیست طراحی سناریوی Integration
قرارداد و داده
- فیلدهای required/optional و مقدار null
- type، enum، precision و واحد پول
- encoding فارسی، راستبهچپ، اعداد و timezone ایران
- نسخه schema و backward/forward compatibility
- payload بزرگ، داده ناقص و فیلد ناشناخته
خطا و تابآوری
- timeout، connection reset و پاسخ کند
- خطاهای قابل retry و غیرقابل retry
- retry storm و backoff
- service unavailable و fallback
- partial failure و rollback/compensation
- duplicate request/event و idempotency
- out-of-order و late event
امنیت و مشاهدهپذیری
- token منقضی، scope ناکافی و role اشتباه
- secret یا PII در log و trace
- Correlation ID در تمام مرزها
- metric و alert برای شکست وابستگی
- audit trail تغییر state حساس
همه موارد برای هر مرز لازم نیست. Risk Workshop کوتاه کمک میکند ترکیبهای پراثر انتخاب شوند.
مثال عملی: Integration Testing مسیر پرداخت
فرض کنید Checkout از Pricing، Inventory، Order DB، Message Broker و درگاه استفاده میکند. یک برنامه لایهای میتواند چنین باشد:
| مرز | سناریو | اوراکل | محیط |
|---|---|---|---|
| Pricing ↔ Checkout | تخفیف درصدی با سقف ۱۰۰ هزار تومان | واحد و مبلغ نهایی یکسان | هر دو سرویس + داده ثابت |
| Checkout ↔ Inventory | دو خرید همزمان برای آخرین کالا | فقط یک رزرو موفق و state سازگار | DB/lock واقعی |
| Order ↔ Broker | تحویل دوباره event پرداخت | یک تغییر وضعیت؛ بدون اثر تکراری | broker container |
| Checkout ↔ Gateway | Callback موفق، تکراری و دیرهنگام | idempotency و تطبیق مبلغ/شناسه | Sandbox یا simulator معتبر |
| Order ↔ Notification | قطع پیامک پس از ثبت سفارش | سفارش حفظ و retry کنترلشده | Stub خطا + تست محدود Provider |
برای هر شکست، timestamp، Request/Trace ID، نسخه سرویس و state قبل/بعد را ثبت کنید. اسکرینشات UI بهتنهایی برای علتیابی مرز سرویسها کافی نیست.
محیط تست یکپارچهسازی را چگونه بسازیم؟
- Local/Containerized: وابستگیهای واقعی سبک با شروع سریع و داده تکرارپذیر
- Ephemeral Environment: محیط موقت برای branch/PR با نسخههای مشخص
- Shared Integration: تعامل چند تیم؛ نیازمند رزرو، health check و جداسازی داده
- Sandbox Provider: اعتبار قرارداد بیرونی با محدودیت مستند
- Staging: سناریوی گستردهتر و پیکربندی نزدیک تولید، نه محیط عمومی برای هر تست شکننده
برای هر محیط مشخص کنید چه چیزی واقعی، Fake یا Virtualized است. راهنمای راهاندازی محیط تست چکلیست نسخه، دسترسی، داده و readiness را ارائه میدهد. برای محیطهای ایزوله نیز مقاله ساخت محیط تست با Docker مفید است.
مدیریت داده در Integration Test
تست باید مالک داده خودش باشد. داده مشترک باعث وابستگی به ترتیب، Fail متناوب و پاکسازی خطرناک میشود.
- داده را با factory/seed نسخهدار بسازید.
- شناسه یکتا برای هر run ایجاد کنید.
- setup و teardown idempotent داشته باشید.
- در تست تراکنش، state تمام datastoreها را ببینید.
- PII واقعی را حذف یا ماسک کنید.
- برای event، offset/topic یا correlation مخصوص run داشته باشید.
- Clock و timezone را کنترل و زمان مورد انتظار را صریح کنید.
Rollback خودکار همیشه کافی نیست؛ وقتی پیام یا cache خارج از تراکنش است، پاکسازی و assertion باید آن اثرها را نیز پوشش دهد.
Integration Test در CI/CD
مجموعه را بر اساس سرعت و وابستگی لایهبندی کنید:
- PR Gate: تستهای قرارداد و یکپارچهسازی باریک، قطعی و سریع.
- Post-Merge: پایگاه داده، broker و چند سرویس واقعی در container/محیط موقت.
- Scheduled/Nightly: سناریوهای بیشتر، سازگاری نسخه و خطاهای کند.
- Pre-Release: Sandbox شریک و مسیرهای end-to-end بحرانی.
- Post-Deploy: smoke مصنوعی و monitoring بدون عملیات مخرب.
تست Flaky را با retry بینهایت پنهان نکنید. قرنطینه، مالک، علت و موعد بازگشت لازم است. duration، failure reason و زمان آمادهسازی محیط را جدا اندازه بگیرید تا گلوگاه آشکار شود.
فرآیند گامبهگام تست یکپارچهسازی
- مرزها را از معماری استخراج کنید. dependency map، جریان داده و مالک سیستم را مشخص کنید.
- ریسک مرز را تحلیل کنید. اثر مالی، امنیتی، زمانی و احتمال تغییر قرارداد.
- Test Basis را جمع کنید. API spec، schema، sequence diagram، SLA و error policy.
- سطح را تعیین کنید. Component Integration یا System Integration؟
- واقعی/مجازی بودن وابستگی را انتخاب کنید. دلیل و محدودیت ثبت شود.
- سناریوهای happy path و failure را طراحی کنید. داده، زمان، تکرار و ترتیب را فراموش نکنید.
- محیط و داده را نسخهدار بسازید. Health Check پیش از اجرا.
- شواهد چندمؤلفهای جمع کنید. trace، log، payload و state.
- در CI لایهبندی کنید. سریعترین بازخورد معتبر نزدیک تغییر اجرا شود.
- شکست را triage و قرارداد را بهروز کنید. نتیجه فقط باگ نیست؛ ممکن است spec یا Test Double قدیمی باشد.
ابزارهای تست یکپارچهسازی
ابزار را بر اساس مرز انتخاب کنید؛ نمونهها رتبهبندی نیستند:
| نیاز | دسته | نمونه |
|---|---|---|
| HTTP/API | Client/Assertion | Postman/Newman، REST Assured، Supertest |
| وابستگی واقعی موقت | Container/Test Environment | Docker Compose، Testcontainers |
| Service Virtualization | Stub/Simulator | WireMock، MockServer |
| Contract | Consumer-Driven Contract | Pact |
| پیام/صف | Broker client و container | ابزار native Kafka/RabbitMQ |
| مشاهدهپذیری | Log/Trace/Metric | OpenTelemetry و backend مانیتورینگ |
سازگاری با تکنولوژی تیم، امنیت داده، هزینه نگهداری، اجرای محلی، امکان شبیهسازی خطا و ادغام CI از تعداد قابلیتهای تبلیغاتی مهمتر است.
معیارهای مفید Integration Testing
- تعداد/درصد رابطهای پرریسک دارای سناریوی معتبر
- نرخ شکست به تفکیک کد، قرارداد، محیط و Flaky
- زمان بازخورد PR و مدت آمادهسازی محیط
- Aging تست قرنطینهشده
- ناسازگاری قرارداد کشفشده پیش از Staging/Production
- نقصهای یکپارچهسازی فراریافته به سطح System یا تولید
تعداد تست یا تعداد Mock معیار کیفیت نیست. ممکن است یک Contract Test کوچک از صد تست سطحی ارزشمندتر باشد.
اشتباهات رایج در Integration Testing
- نامگذاری Unit Test بهعنوان Integration: هیچ وابستگی یا قرارداد واقعی درگیر نیست.
- فقط happy path: timeout، retry و partial failure در تولید ظاهر میشوند.
- Mock همه وابستگیها: drift قرارداد پنهان میماند.
- تست مستقیم محیط مشترک بدون isolation: نتیجه به ترتیب و داده دیگران وابسته میشود.
- Sleep ثابت برای async: تست کند و Flaky میشود؛ polling با timeout و شرط مشخص بهتر است.
- اعتماد کامل به Sandbox: تفاوت آن با Production مستند نمیشود.
- پاکسازی خطرناک: teardown با query یا شناسه گسترده داده دیگران را حذف میکند.
- ثبت فقط response: state، event و trace دیده نمیشوند.
- Big Bang دیرهنگام: چندین مرز همزمان تغییر و علت مبهم میشود.
- یکی گرفتن Retest و Regression: اصلاح مرز تایید میشود ولی شعاع اثر بررسی نمیشود.
چکلیست تست یکپارچهسازی
- Component Integration و System Integration تفکیک شدهاند.
- مرز، مالک، قرارداد و نسخه هر طرف مشخص است.
- معنای داده—نه فقط schema—بررسی میشود.
- happy path، خطا، timeout، retry و duplicate پوشش دارند.
- transaction، rollback و state چند جزء مشاهده میشود.
- Test Doubleها محدودیت و تست متناظر با Provider واقعی دارند.
- داده هر run مستقل و پاکسازی امن است.
- Correlation ID، log و trace برای علتیابی آمادهاند.
- تستها در CI بر اساس سرعت و پایداری لایهبندی شدهاند.
- Flakyها قرنطینه، مالک و موعد اصلاح دارند.
- تفاوت Sandbox/Staging با Production مستند است.
سؤالات متداول تست یکپارچهسازی
تست یکپارچهسازی بعد از Unit و قبل از System است؟
از نظر هدف میان این دو قرار دارد، اما در CI میتواند همزمان با توسعه اجرا شود. طراحی آن نباید تا پایان همه Unit Testها صبر کند. System Integration نیز ممکن است در نقاط مختلف و با Sandbox شریک انجام شود.
آیا تست API همان Integration Testing است؟
نه همیشه. API Test میتواند یک endpoint از کل سیستم را جعبه سیاه بسنجد یا تعامل واقعی چند سرویس را آزمایش کند. Test Object، وابستگی و هدف مشخص میکند تست Integration است یا نه.
آیا Integration Test باید پایگاه داده واقعی داشته باشد؟
اگر رفتار repository، query، transaction یا migration هدف است، پایگاه داده سازگار ارزش بالایی دارد. برای منطق بالادست میتوان Fake استفاده کرد، به شرط اینکه تست جداگانه drift با دیتابیس واقعی را پوشش دهد.
Contract Test جای End-to-End را میگیرد؟
خیر. Contract سازگاری تعامل تعریفشده را سریع میسنجد؛ شبکه، پیکربندی، امنیت، ترتیب عملیاتی و رفتار کامل Provider همچنان به تستهای دیگر نیاز دارند. تعداد کمی E2E بحرانی کنار Contract منطقی است.
تفاوت Stub و Mock چیست؟
Stub پاسخ کنترلشده میدهد؛ Mock علاوه بر آن معمولاً انتظار تعامل را تایید میکند. در عمل کتابخانهها واژهها را متفاوت بهکار میبرند؛ مهم این است که بدانید Double چه چیزی را شبیهسازی و چه چیزی را پنهان میکند.
جمعبندی
تست یکپارچهسازی کیفیت اتصالها را میسنجد: قرارداد، معنا، state، زمان، شکست و سازگاری. از مرزهای پرریسک شروع کنید، Integration داخلی و بیرونی را جدا کنید، وابستگی واقعی و مجازی را آگاهانه ترکیب کنید و شواهد چندسرویسی بسازید. Unit Test سالم شرط لازم است، اما تا وقتی اجزا در شرایط واقعی همکاری نکردهاند، سیستم فقط مجموعهای از قطعات سالمِ آزموننشده در کنار هم است.

