API मॉकिंग और सर्विस वर्चुअलाइज़ेशन

API mocking का मतलब है कि system under test जिस API पर निर्भर है, उसकी जगह एक ऐसा stand-in रखना जो उसकी HTTP requests का जवाब वैसे दे जैसा test को चाहिए। उदाहरण: एक online store की order service एक payment provider को call करती है। Test environment में provider का base URL एक stub server की ओर इशारा करता है, जो भेजे गए card token के हिसाब से POST /v1/charges का जवाब "captured", "declined" या 503 से देता है, ताकि असली पैसों का लेन-देन किए बिना हर payment path टेस्ट हो सके।

Service virtualization यही idea पूरे test environment के स्तर पर है: पूरे dependent systems simulate किए जाते हैं, अक्सर recorded असली traffic से, और कई teams उन्हें share करती हैं। ISTQB Foundation syllabus stubs, drivers, simulators और service virtualization को उन test environment items में गिनता है जो test implementation के दौरान तैयार किए जाते हैं। Contract testing ने तय किया कि API क्या वादा करता है; अच्छा mock ठीक वही वादे निभाता है। Component testing वाली test doubles की शब्दावली (stub, spy, mock, fake) अब code से network पर आ जाती है।

यह क्यों ज़रूरी है

असली dependencies अक्सर testing रोक देती हैं: दूसरी team की service अभी बनी नहीं, third-party sandbox बंद है, calls पर पैसा लगता है या rate limit आ जाती है, और shared data runs के बीच बदल जाता है। इन पर निर्भर tests ऐसे कारणों से fail होते हैं जिनका code under test से कोई लेना-देना नहीं।

सबसे बड़ी बात: doubles error paths को टेस्ट करने लायक बनाते हैं। असली payment provider माँगने पर 503, 429 या 15 seconds बाद आने वाला जवाब नहीं देगा, जबकि यही वे पल हैं जब customer से दो बार पैसा कटता है या orders खो जाते हैं। कीमत यह है कि double उतना ही अच्छा है जितना वह असली API जैसा है; गलत double green tests और production में failures देता है।

जब dependency एक API हो: stubs, mocks और fakes

System under test असली HTTP requests भेजता है, और उनका जवाब असली service की जगह कोई और देता है। सिर्फ़ configuration बदलता है: dependency का base URL, जैसे PAYMENT_API_URL, CI में double की ओर और staging में असली provider की ओर इशारा करता है। रोज़ के API काम में "mock" शब्द ढीले ढंग से इस्तेमाल होता है, और "mock server" आम तौर पर stub की तरह configure होता है। जब फ़र्क मायने रखे, तो पूछें कि double असल में क्या करता है:

  • Stub: हर matching request के लिए तैयार response लौटाता है, जैसे GET /v1/rates/RUH → 200 {"fee": 18}, और कुछ याद नहीं रखता। Test आपके system का result जाँचता है, जैसे दिखाई गई fee (state verification)।
  • Mock: stub की तरह जवाब देता है, लेकिन उसमें पहले से उन requests की expectations programmed होती हैं जो उसे मिलनी चाहिए, जैसे Idempotency-Key header के साथ ठीक एक POST /v1/charges। Call न हो, दोहराई जाए या अलग हो, तो test fail होता है (behaviour verification)। जो test बाद में request log पढ़ता है, वह double को spy की तरह इस्तेमाल करता है।
  • Fake: अपनी state वाला सरल लेकिन काम करने वाला implementation, आम तौर पर memory में: POST /v1/orders order store करता है और GET /v1/orders/{id} उसे लौटाता है। जब calls एक-दूसरे पर निर्भर हों तब उपयोगी, लेकिन इसका अपना logic भी गलत हो सकता है।
  • Service virtualization: shared test environment में simulated dependent system, जो अक्सर असली traffic record करके बनता है, state, delays और failures के साथ, कभी-कभी HTTP के अलावा दूसरे protocols के लिए भी। इसे बनाना और maintain करना महँगा है, और अक्सर इसकी owner platform या test-environment team होती है। कुछ teams इस term को API mocking का पर्याय मानती हैं; फ़र्क scope और ownership का है।
API base URL के पीछे stub सिर्फ़ जवाब देता है, mock मिली requests भी जाँचता है, fake अपनी state रखता है, और service virtualization shared environment के लिए पूरा system simulate करता है। वैचारिक मॉडल

Stub

तैयार responses से जवाब देता है

उदाहरण:
GET /v1/rates/RUH → 200 {"fee": 18}
क्या याद रखता है:
कुछ नहीं: एक ही request को हमेशा एक ही जवाब
Test क्या जाँचता है:
आपके system का result (state verification)
किस बात से सावधान रहें:
असली API से drift

Mock

जवाब देता है और requests जाँचता है

उदाहरण:
Idempotency-Key header के साथ ठीक एक POST /v1/charges
क्या याद रखता है:
उसे मिली requests
Test क्या जाँचता है:
आपके system की भेजी requests (behaviour verification)
किस बात से सावधान रहें:
इतनी सख़्त expectations कि हानिरहित बदलाव tests तोड़ दें

Fake

सरल लेकिन काम करने वाला implementation

उदाहरण:
POST /v1/orders order store करता है; GET /v1/orders/{id} उसे लौटाता है
क्या याद रखता है:
अपना data, आम तौर पर memory में
Test क्या जाँचता है:
एक-दूसरे पर निर्भर calls के पार आपके system का result
किस बात से सावधान रहें:
इसका अपना logic भी गलत हो सकता है

Service virtualization

Simulate किया गया dependent system

उदाहरण:
Record किया गया असली traffic, state, delays और failures के साथ replay
क्या याद रखता है:
Calls के बीच state, जैसे record या configure की गई
Test क्या जाँचता है:
Shared test environment में पूरे flows
किस बात से सावधान रहें:
लागत और maintenance; recordings में personal data और tokens हो सकते हैं

ये आम भूमिकाएँ हैं: tools और teams अक्सर ये नाम ढीले ढंग से इस्तेमाल करते हैं, इसलिए पूछें कि double असल में क्या करता है।

आज़माएँ: Mock API रिस्पॉन्स जनरेटर आज़माएँ: Mock JSON जनरेटर

कब mock करें, और कब असली API इस्तेमाल करें

हर dependency और हर test level के लिए अलग फ़ैसला करें: जो आपका नहीं है या जिस पर आपका नियंत्रण नहीं, उसे बदलें, और test को जो साबित करना है उसके लिए असली चीज़ इस्तेमाल करें। System under test को खुद कभी न बदलें। System integration और end-to-end checks के लिए असली dependency या provider का sandbox रखें। जिस security control को टेस्ट कर रहे हैं उसे कभी stub न करें: हर token स्वीकार करने वाला stub authentication के बारे में कुछ साबित नहीं करता। Double तब फ़ायदेमंद है जब:

  • Dependency अभी मौजूद नहीं: तय किए गए OpenAPI document से बना stub testing को जल्दी शुरू करने देता है।
  • Dependency किसी third party की है जो धीमी है, हर call के पैसे लेती है, request rate सीमित करती है या जिसका कोई काम का sandbox नहीं।
  • आपको ऐसे responses चाहिए जो असली service माँगने पर नहीं देगी: Retry-After के साथ 429, 503, timeout, ऐसी body जो JSON नहीं है, खाली list।
  • Tests को CI में तेज़ और दोहराने लायक होना है, shared environments की हालत चाहे जो हो।

Worked example: checkout पर payment failures

Payment provider का sandbox सिर्फ़ successful charge या declined card लौटाता है। Requirement R-21: "Declined card पर order UNPAID रहता है और कारण दिखाया जाता है। Provider busy या unavailable हो तो order UNPAID रहता है और customer से बाद में कोशिश करने को कहा जाता है। 10 seconds में जवाब न आए तो order PAYMENT_PENDING हो जाता है और charge status बाद में जाँचा जाता है; दोबारा charge कभी नहीं किया जाता।" Test environment payment base URL को एक stub server की ओर करता है, हर card token के लिए एक stub के साथ:

  • सिर्फ़ पहली दो rows sandbox से बनाई जा सकती हैं; stubs के बिना बाकी चार rows शायद पहली बार production में, असली customers के सामने आतीं।
  • tok_slow के लिए stub काफ़ी नहीं: order status के अलावा test यह जाँचता है कि ठीक एक charge request आई, तब भी जब customer दोबारा Pay दबाए, या तो mock की expectation से या बाद में request log पढ़कर (spy)।
  • tok_broken R-21 में नहीं है: यह tester के सवाल "अगर body JSON न हो तो?" से आया, और team ने इसे unavailable provider की तरह handle करना चुना।
Stub server for the payment provider (test environment only)
Request: POST /v1/charges; the stub is chosen by "token" in the body

token         Stub response                         Expected in our system
------------  ------------------------------------  ------------------------------
tok_ok        201 {"status":"captured"}             order PAID, receipt sent
tok_declined  422 {"error":"card_declined"}         order UNPAID, reason shown
tok_busy      429, Retry-After: 30                  order UNPAID, "try again later"
tok_down      503 {"error":"unavailable"}           order UNPAID, "try again later"
tok_slow      201, but only after 15 s              at 10 s: PAYMENT_PENDING and
                                                    exactly one charge request
tok_broken    200, body is an HTML error page       handled as unavailable, logged

आज़माएँ: API स्टेटस कोड सिम्युलेटर आज़माएँ: Mock एरर रिस्पॉन्स जनरेटर

Mocking के जोखिम और उन्हें कैसे रोकें

Double किसी दूसरे system के बारे में एक assumption है, जो test code के रूप में लिखा गया है। हर जोखिम उस assumption के गलत होने का एक तरीका है:

  • Drift: provider किसी field का नाम या अपना error format बदल देता है, double पुराना जवाब देता रहता है, और tests green रहते हुए production में failure होता है। Stub bodies को provider के contract से validate करें, और ऐसे contract tests चलाएँ जो वही requests provider के sandbox को भेजें और उसके जवाबों की doubles के जवाबों से तुलना करें, किसी तय schedule पर, जैसे दिन में एक बार, और हर provider release पर। Provider जिन consumer-driven contracts को verify करता है, वे दूसरी तरफ़ से यह कमी पूरी करते हैं।
  • अवास्तविक व्यवहार: doubles तुरंत जवाब देते हैं और कभी rate limit नहीं लगाते। जहाँ timing मायने रखती है वहाँ realistic delays जोड़ें, और कुछ tests असली service पर रखें।
  • Over-mocking: इतने doubles कि test सिर्फ़ doubles को exercise करे, या headers और call order पर इतनी सख़्त expectations कि हानिरहित बदलाव भी tests तोड़ दें।
  • Leaks: staging या production configuration में छूटा हुआ stub URL। हर environment में लिखा हो कि कौन-सी dependencies असली हैं, और deployment checks इसकी पुष्टि करें।
  • Recorded data: service virtualization के लिए record किए गए traffic में personal data और access tokens हो सकते हैं। Store या share करने से पहले उन्हें mask करें।

आज़माएँ: API स्कीमा वैलिडेटर आज़माएँ: रिस्पॉन्स कॉन्ट्रैक्ट कम्पेरेटर

आम गलतियाँ

  • हर double को mock कहना और यह तय न करना कि वह क्या करता है: सिर्फ़ जवाब देने वाला stub duplicate charge नहीं पकड़ सकता।
  • Stub responses contract या recorded असली response से नहीं, याद से लिखना।
  • सिर्फ़ success path को stub करना, जिससे timeouts, retries और error messages कभी टेस्ट नहीं होते।
  • Doubles पर चलने वाले green suite को integration के काम करने का सबूत मानना।
  • Doubles को बिना owner के छोड़ देना, जिससे provider के बदलने पर कोई उन्हें update नहीं करता।
  • Personal data या live tokens वाला recorded traffic repository में commit करना।

QA का नज़रिया

अक्सर tester तय करता है कि doubles क्या लौटाएँ, क्योंकि कीमती responses वही error cases हैं जिन्हें वह design करता है। Refinement में हर external dependency के लिए पूछें: क्या sandbox है? Contract कौन-से errors और limits document करता है? Timeout कैसे simulate करेंगे? Stubs का owner कौन है? जवाब हर test level के हिसाब से test plan में लिखें।

Reports में लिखें कि result double से आया या असली service से; stub पर pass कमज़ोर evidence है। Bug reports के साथ stub definition attach करें। Double और असली API के बीच का फ़र्क एक finding है: या तो double गलत है, या provider ने अपना contract तोड़ा। किसी dependency से जुड़े production incident के बाद वह response stubs में जोड़ें।

अभ्यास

Shipping-rate API के लिए doubles की योजना बनाएँ

आपका काम

Checkout एक shipping provider से delivery options दिखाता है। Requirement CHK-7 और नीचे दिए contract excerpt के आधार पर stubs की योजना बनाएँ, तय करें कि किस statement के लिए stub की जगह mock चाहिए, और बताएँ कि अब भी असली sandbox पर क्या चाहिए और drift कैसे पकड़ेंगे।

सामग्री
Requirement CHK-7 (checkout, delivery step)
1. Delivery options fee के हिसाब से sorted दिखाएँ, सबसे सस्ता पहले। अगर provider
   कोई option न लौटाए, तो "इस पते पर delivery उपलब्ध नहीं है" दिखाएँ।
2. अगर provider 5 seconds में जवाब न दे, या 5xx status लौटाए, तो 25.00 SAR
   की fixed fee दिखाएँ और event log करें।
3. Options को हर city और weight के लिए 10 minutes तक cache करें: हर city और
   weight पर provider को एक call, हर page view पर एक call नहीं।

Provider contract (excerpt)
GET /v2/rates?city={code}&weightKg={number}
200  {"rates": [{"service": "standard", "fee": 18.00, "days": 3}, ...]}
400  {"error": "invalid_city"}
429  Retry-After: {seconds}
चरण
  1. CHK-7 के हर statement को exercise करने वाले provider responses लिखें, errors समेत।
  2. Stub table लिखें: request, stub response, checkout का expected behaviour।
  3. वह scenario चिह्नित करें जिसे request verification चाहिए, और test क्या assert करता है।
  4. लिखें कि अब भी असली sandbox पर क्या चलना चाहिए, और drift पकड़ने का एक तरीका।
मॉडल उत्तर दिखाएँ
मॉडल उत्तर

Statement 1: जानबूझकर unsorted options (35.00, 18.00, 22.00) के साथ 200 → 18.00 पहले, क्योंकि पहले से sorted stub data missing sort नहीं पकड़ सकता; "rates": [] के साथ 200 → "इस पते पर delivery उपलब्ध नहीं है"।

Statement 2: 503 → fixed fee 25.00 और एक log entry; 7 seconds बाद जवाब → fixed fee और log entry; लगभग 4 seconds बाद जवाब → provider के options, ताकि limit दोनों तरफ़ से टेस्ट हो।

CHK-7 में नहीं: 400 invalid_city और Retry-After के साथ 429। इनके stubs भी बनाएँ और product owner से पूछें कि हर एक में क्या दिखना चाहिए।

Statement 3 के लिए mock या spy चाहिए: cache हो या न हो, page एक जैसा दिखता है, इसलिए caching सिर्फ़ request log से दिखती है। एक ही city और weight के लिए तीन visits → ठीक एक GET /v2/rates; 10 minutes बाद, या test clock आगे करके visit → ठीक एक और; उसी city पर दूसरा weight → उसकी अपनी call, क्योंकि सिर्फ़ city के आधार पर बना cache गलत fees दिखाएगा।

असली sandbox: कुछ tests जो साबित करें कि provider असली request स्वीकार करता है (parameter names, authentication) और उसका response parse होता है। Drift: CI में stub bodies को provider के schema से validate करें, और हर provider release पर sandbox का ताज़ा response stubs से compare करें।

अक्सर पूछे जाने वाले सवाल

क्या mock server और mock एक ही हैं?

सख़्ती से नहीं। जो mock server सिर्फ़ तैयार responses लौटाता है, वह stub की तरह काम कर रहा है। वह mock या spy तब बनता है जब test यह भी जाँचे कि उसे कौन-सी requests मिलीं। Tools ये शब्द ढीले ढंग से इस्तेमाल करते हैं, इसलिए नाम पर बहस करने की जगह बताएँ कि double क्या करता है।

API mocking और service virtualization में क्या फ़र्क है?

ज़्यादातर scope और ownership का। API mocking का मतलब आम तौर पर वे stubs या mocks हैं जो कोई team अपने tests के लिए define करती है। Service virtualization shared test environment में पूरे dependent systems simulate करता है, अक्सर recorded traffic से और state, delays व failures के साथ, और अक्सर इसे platform या test-environment team चलाती है। कुछ teams दोनों terms को एक ही अर्थ में इस्तेमाल करती हैं।

अगर हम mocks इस्तेमाल करते हैं, तो क्या contract tests और end-to-end tests की अब भी ज़रूरत है?

हाँ। Mocks आपके system को isolation में टेस्ट करने और error paths force करने देते हैं। Contract tests जाँचते हैं कि mocks अब भी असली API से मेल खाते हैं। Staging या provider के sandbox में असली integration पर कुछ tests पुष्टि करते हैं कि wiring, authentication और configuration काम करते हैं। हर एक वह cover करता है जो बाकी नहीं कर सकते।

क्या tester code लिखे बिना mocks के साथ काम कर सकता है?

अक्सर हाँ। कई mock servers JSON या YAML files से या user interface से configure होते हैं, और stub मूल रूप से match करने वाली एक request और लौटाने वाला एक response है। Mutqan के mock tools ऐसी files के लिए response bodies और error payloads generate करते हैं, और API Status Code Simulator आपको ऐसा endpoint देता है जो कोई भी status code लौटाता है, 10 seconds तक के optional delay और custom JSON body के साथ। यह client की error handling टेस्ट करने के लिए काफ़ी है, और उसके timeouts के लिए भी, जब वे 10 seconds से कम हों।

संदर्भ

  • ISTQB Certified Tester Foundation Level (CTFL) v4.0ISTQB · 2023सॉफ़्टवेयर टेस्टिंग का फ़ाउंडेशन पाठ्यक्रम: टेस्ट स्तर और प्रकार, टेस्ट डिज़ाइन तकनीकें, टेस्ट प्रबंधन और टूल।
  • Test Double (Martin Fowler)martinfowler.com · 2006test doubles के लिए Gerard Meszaros की शब्दावली — dummy, fake, stub, spy और mock — जैसा Martin Fowler ने सारांशित किया।
  • Mocks Aren't Stubs (Martin Fowler)martinfowler.com · 2007state verification और behavior verification का अंतर, और test-driven development की classical और mockist शैलियों का अंतर।
  • Contract Test (Martin Fowler)martinfowler.com · 2011Contract tests: समय-समय पर होने वाली जाँचें कि test double पर किए गए calls वही नतीजे लौटाते हैं जो असली बाहरी सेवा पर वही calls लौटाते।

Mutqan tools से अभ्यास करें

ऐसा सार्वजनिक endpoint पाएँ जो कोई भी HTTP स्टेटस कोड लौटाए, वैकल्पिक देरी और कस्टम JSON बॉडी के साथ, ताकि क्लाइंट की error हैंडलिंग टेस्ट हो सके।

API टेस्टिंग

प्लेसहोल्डर वाले टेम्पलेट से mock JSON बनाएँ ({{name}}, {{uuid}}, {{int:1-10}}, {{date}}, {{pick:a|b}})।

मॉकिंग

API रिस्पॉन्स को JSON Schema या OpenAPI रिस्पॉन्स स्कीमा के आधार पर जाँचें।

API टेस्टिंग

और गहराई से

इस topic में आपकी प्रगति

QA रोडमैप का हिस्सा