VPS वर self-hosted API mocking आणि testing
Mock server आणि API test runner ची कामे वेगळी आहेत. WireMock stubs git मध्ये, Hurl suites CI मध्ये चालवा आणि VPS पुन्हा बांधल्यावरही reports जतन करा.
एकाच repository मध्ये सामायिक केलेली दोन कामे
Self-hosted API mocking आणि testing ही दोन वेगवेगळी कामे आहेत. त्यांना एकच काम मानल्यास एक आठवडा वाया जाऊ शकतो. CI मधून ज्या dependency ला call करता येत नाही, तिच्या जागी mock server काम करतो: payment provider, partner API, rate limited upstream किंवा दुसऱ्या team ने अद्याप release न केलेली service. API test runner तुमच्या स्वतःच्या endpoints ना निश्चित क्रमाने call करतो आणि responses ची पडताळणी करतो. एका response मधील values पुढील request मध्ये वापरतो.
ही दोन कामे एकमेकांना overlap होत नाहीत. Mock server कधीही pass किंवा fail report करत नाही. Card decline झाल्यावर payment provider ने काय return करावे, याबाबत test runner कोणतेही मत देत नाही. आधीपासून server भाड्याने घेणाऱ्या बहुतेक teams शेवटी प्रत्येकी एक service चालवतात. त्या दोन्ही services समान Docker Compose file ने सुरू केल्या जातात आणि समान pull request मध्ये review केल्या जातात.
स्वतः होस्ट केलेले API mocking आणि testing का करावे?
तुमचे fixtures हे production च्या आकाराचे डेटा असतात. API test मधील request body हा नाव बदललेला खरा customer record असू शकतो. किंवा तो नाव न बदललेलाही असू शकतो, कारण कोणीही तपासलेले नसते. Recorded stubs याहून धोकादायक असतात: proxy recording मध्ये upstream ने प्रत्यक्षात परत केलेली कोणतीही माहिती साठवली जाते. त्यामुळे recording करून तयार केलेल्या stub directory मध्ये प्रत्येक file कोणी तपासेपर्यंत live tokens आणि customer email addresses राहू शकतात. Hosted service वर हा डेटा दुसऱ्या संस्थेचा security incident आणि तुमचे data disclosure बनतो.
दुसरे कारण म्हणजे reachability. Private address वर bind केलेली service hosted runner कडून reachable नसते. त्यामुळे test अजिबात चालत नाही. प्रत्येक workaround ची काही ना काही किंमत असते. API ची चाचणी घेण्यासाठी ती internet वर publish केल्यास ती private ठेवण्यामागचे कारणच नष्ट होते. Tunnel किंवा public staging copy ही देखभाल करावी लागणारी आणखी एक system असते. तसेच प्रत्येक release दरम्यान staging copy production पासून वेगळी होत जाते. त्याच private network वरील runner service ला थेट call करतो आणि यापैकी कशाचीही गरज भासत नाही. self-hosted GitHub Actions runner मागील व्यावहारिक कारण हेच आहे.
तुम्ही कोणता self-hosted mock server चालवावा?
यापैकी प्रत्येक server तुमच्या मालकीच्या machine वर container म्हणून चालतो. महत्त्वाचा प्रश्न असा आहे की प्रत्येक server कोणत्या गोष्टीला अंतिम आधार मानतो. Container पुन्हा तयार केल्यावर तुमचे काहीही नुकसान होणार नाही की त्यासाठी पूर्ण दुपार खर्च होईल, हे त्यावर ठरते.
- WireMock प्रत्येक stub
mappings/directory मध्ये JSON file म्हणून ठेवतो. मोठे response body__files/मध्ये ठेवले जातात. Imagewiremock/wiremockआहे, container मधील root directory/home/wiremockआहे आणि तो recording proxy म्हणूनही चालतो. Files disk वर असल्यामुळे हा mock इतर code प्रमाणे git मध्ये ठेवता येतो. - Mockoon CLI संपूर्ण mock API एका JSON data file मध्ये ठेवतो. तो
npm install -g @mockoon/cliने install करूनmockoon-cli start --data ./data-file.jsonने सुरू करा किंवा ती file bind mount करूनmockoon/cliimage चालवा. Desktop app हीच file edit करते. त्यामुळे UI मध्ये design करून तो result commit करणे सुसंगत राहते. - MockServer
mockserver/mockserverimage मधून चालतो आणि port 1080 वर listen करतो. Expectations त्याच्या REST API द्वारे पाठवता येतात. Test code मधून हे सोयीचे आहे; मात्र deployment साठी ते धोकादायक आहे. HTTP call ने तयार केलेली expectation container restart झाल्यावर नाहीशी होते. कायमस्वरूपी stubs साठी त्याची JSON initialization file वापरा. - Prism स्वतंत्र stub files ऐवजी तुमच्या OpenAPI document वरून mock तयार करतो. तो
npm install -g @stoplight/prism-cliने install करा आणि नंतरprism mock openapi.yamlचालवा. Container मध्ये-h 0.0.0.0जोडा, कारण Prism default ने localhost वर bind होतो. तसे न केल्यास तो container च्या बाहेरून accessible राहणार नाही. - Microcks हा मोठा पर्याय आहे. त्यात OpenAPI documents आणि Postman collections import करण्यासाठी web UI आहे. त्यानंतर तो त्यांना mocks म्हणून serve करतो आणि contract tests चालवतो. पूर्ण install साठी MongoDB आणि Keycloak आवश्यक आहेत. त्याच्या asynchronous features साठी Kafka देखील आवश्यक आहे. All-in-one
microcks-uberimage मध्ये in-memory MongoDB समाविष्ट आहे. Project documentation नुसार ते ephemeral use साठी योग्य आहे. त्यामुळे त्या UI मध्ये तयार केलेली कोणतीही गोष्ट disposable समजा आणि source artifacts git मध्ये ठेवा.
कोणता self-hosted API test runner चालवावा?
येथील काम ही एक क्रमवार प्रक्रिया आहे: authenticate करा, order तयार करा, तो पुन्हा वाचा आणि state बदलल्याची खात्री करा. एका response मधून मिळवलेली value पुढील request मध्ये वापरावी लागते. Calls दरम्यान state जतन करू न शकणारे tool हे health check आहे, API test नाही.
- Hurl एका binary मधून HTTP requests असलेल्या plain text files चालवते.
[Captures]section response मधून values काढतो,[Asserts]section त्यांची तपासणी करतो आणि--testsummary व exit code सह त्याला test runner मध्ये रूपांतरित करतो. August 2026 पर्यंत Version 8.0.1 current आहे. - Bruno CLI
.brufiles असलेले folder चालवते.npm install -g @usebruno/cliने install करा आणि नंतरbru run folder --env Local --reporter-junit results.xmlचालवा. Collection format हे डिझाइननुसार directory मधील text files आहेत. त्यामुळे review दरम्यान diffs वाचणे सोपे असते. - Newman Postman च्या बाहेर Postman collections चालवते:
npm install -g newman, त्यानंतरnewman run collection.json -r cli,junit --reporter-junit-export results.xml. मात्र format ही अडचण आहे. Collection हा एक exported JSON blob असतो. त्यामुळे editing Postman मध्ये होते आणि git मधील file ही कालांतराने stale होणारी copy असते. - Schemathesis हा वेगळ्या प्रकारचा check आहे. तो OpenAPI schema वाचतो आणि schema नुसार अशक्य असायला हवेत असे responses निर्माण करण्याचा प्रयत्न करणारे cases तयार करतो:
uvx schemathesis run https://your.api/openapi.json. तो crashes आणि contract violations शोधतो. त्याला तुमच्या business rules बद्दल काही माहिती नसते. त्यामुळे scripted suite ची जागा घेण्याऐवजी तो तिच्या शेजारी वापरला जातो. - Hoppscotch self hosted हा web UI पर्याय आहे आणि त्यासाठी Postgres instance आवश्यक आहे. Install करण्यापूर्वी हा tradeoff समजून घ्या: collections तुमच्या repository मध्ये नसून database मध्ये साठवले जातात.
एक टाळण्यासारखा पर्याय आहे. Step CI अजूनही tool roundups मध्ये दिसतो आणि त्याचे YAML workflow format वाचायला सोपे आहे. मात्र repository ला शेवटचा commit August 2024 मध्ये मिळाला. तुमच्या CI आणि API यांच्या मध्ये चालणाऱ्या program साठी unmaintained code असणे योग्य नाही.
फायरवॉलच्या मागे mock server ठेवा
खालील setup payment provider च्या जागी WireMock चालवते. compose file format तुमच्यासाठी नवीन असल्यास, VPS वर Docker Compose या विभागात या section मध्ये गृहीत धरलेले lifecycle commands दिले आहेत.
services:
mock-payments:
image: wiremock/wiremock:3.13.2
command: ["--verbose"]
volumes:
- ./mocks/payments:/home/wiremock
ports:
- "127.0.0.1:8080:8080"
restart: unless-stoppedPort वरील 127.0.0.1: prefix महत्त्वाचा आहे. साधा 8080:8080 वापरल्यास mock तुमच्या public IP सह प्रत्येक interface वर publish होतो. ufw ने तो port deny केला तरी तो उपलब्ध राहतो, कारण Docker स्वतःचे rules DOCKER iptables chain मध्ये लिहिते आणि ufw चे INPUT rules तपासण्यापूर्वी त्यांचे मूल्यांकन होते. त्याऐवजी loopback address किंवा private interface address ला bind करा. त्यामुळे kernel बाहेरून आलेले connection कधीही स्वीकारत नाही.
त्यानंतर test केले जाणारे service mock कडे निर्देशित करा. Service त्याच compose project मध्ये चालत असल्यास mock चा base URL http://mock-payments:8080 असतो, कारण compose स्वतःच्या network वर service names resolve करते. Service host वर चालत असल्यास तो http://127.0.0.1:8080 असतो. हे environment variable द्वारे सेट करा. ते code मध्ये कधीही ठेवू नका; अन्यथा test URL production मध्ये पोहोचेल.
Stubs ./mocks/payments/mappings/ मध्ये ठेवा. प्रत्येक JSON file स्वतंत्र असावी.
{
"request": {
"method": "POST",
"urlPath": "/v1/charges",
"bodyPatterns": [{ "matchesJsonPath": "$.amount" }]
},
"response": {
"status": 201,
"headers": { "Content-Type": "application/json" },
"jsonBody": { "id": "ch_test_001", "status": "succeeded", "amount": 4200 }
}
}ते सुरू करा. त्यानंतर प्रत्यक्षात काय load झाले ते तपासा.
docker compose up -d --wait mock-payments
curl -fsS http://127.0.0.1:8080/__admin/mappings--wait container healthy असल्याचे report करेपर्यंत थांबते. हे कार्य करते, कारण WireMock image मध्ये त्याच्या /__admin/health endpoint साठी HEALTHCHECK उपलब्ध असते. mappings call server ने read केलेले सर्व stubs दाखवते. तुम्ही लिहिलेला stub त्या यादीत नसेल, तर तो load झालेला नाही. File mounted root मध्ये न ठेवता mappings/ अंतर्गत आहे का ते तपासा. JSON parse होत आहे का तेही तपासा.
Request आल्यावर कोणताही stub match झाला नाही, तर WireMock 404 उत्तर देते. त्याच्या body ची सुरुवात Request was not matched ने होते. त्यानंतर server कडे असलेल्या सर्वात जवळच्या stub विरुद्धचा diff दिला जातो. काहीही बदलण्यापूर्वी तो diff वाचा, कारण त्यात नेमके कोणते field वेगळे आहे ते दिलेले असते. बहुतेक वेळा तो /v1/charge असलेला path असतो, तर stub मध्ये /v1/charges असते.
कॉलदरम्यान स्थिती जतन होईल अशा क्रमाने चाचणी लिहा
Hurl फाइल्स साध्या मजकूराच्या असतात. प्रकल्पाच्या releases मधील deb इंस्टॉल करा.
VERSION=8.0.1
curl --location --remote-name https://github.com/Orange-OpenSource/hurl/releases/download/$VERSION/hurl_${VERSION}_amd64.deb
sudo apt update && sudo apt install ./hurl_${VERSION}_amd64.debmock विरुद्ध तुमच्या स्वतःच्या API ची चाचणी घेणारा suite tests/checkout.hurl मध्ये आहे.
POST {{base_url}}/orders
Content-Type: application/json
{
"sku": "ssd-1tb",
"amount": 4200
}
HTTP 201
[Captures]
order_id: jsonpath "$['id']"
GET {{base_url}}/orders/{{order_id}}
HTTP 200
[Asserts]
jsonpath "$.status" == "paid"
jsonpath "$.charge_id" == "ch_test_001"[Captures] ब्लॉकमुळे ही दोन असंबंधित विनंत्यांऐवजी API चाचणी बनते. order_id पहिल्या response मधून वाचले जाते आणि दुसऱ्या विनंतीच्या URL मध्ये interpolated केले जाते. charge_id वरील assertion हा संपूर्ण चाचणीचा मुख्य भाग आहे: यामुळे तुमच्या सेवेने payment provider ला कॉल करून परत आलेली माहिती साठवली हे सिद्ध होते. तसेच, ती ज्या मूल्याशी तुलना करते ते WireMock stub मध्ये तुम्ही लिहिलेले मूल्य आहे. आता एकाच फाइलमध्ये या flow चे दोन्ही भाग समाविष्ट आहेत.
hurl --test --variable base_url=http://127.0.0.1:3000 \
--report-junit reports/junit.xml \
--report-json reports/json \
tests/यशस्वी run मध्ये प्रत्येक फाइलसाठी एक ओळ आणि त्यानंतर summary दिसते.
tests/checkout.hurl: Success (2 request(s) in 61 ms)
Executed files: 1
Executed requests: 2 (30.1/s)
Succeeded files: 1 (100.0%)
Failed files: 0 (0.0%)
Duration: 64 msअपयश आल्यास error: Assert failure फाइल आणि line number सह दाखवते. त्यानंतर मिळालेले मूल्य आणि अपेक्षित मूल्य दाखवले जाते. hurl non zero स्थितीसह exit होते, त्यामुळे CI थांबते. तुम्हाला status मध्ये pending दिसत असेल, पण तुम्ही paid अपेक्षित केले असेल, तर तुमच्या सेवेने mock च्या response वर प्रक्रिया केलेली नाही. पुढे /__admin/requests येथील WireMock request journal तपासा. कॉल mock पर्यंत पोहोचला की नाही हे त्यातून दिसते.
तुमच्या स्वतःच्या CI runner कडून suite सुरू करा
त्याच box वर runner नोंदणीकृत असल्यास workflow लहान राहतो. Runner ही host वरील साधी process असते. त्यामुळे docker आणि hurl या host वर install केलेले असणे आवश्यक आहे. Hosted image मधील कोणतीही गोष्ट आपोआप मिळत नाही.
name: api-tests
on: [push]
jobs:
hurl:
runs-on: self-hosted
steps:
- uses: actions/checkout@v4
- name: Start the mock
run: docker compose up -d --wait mock-payments
- name: Run the suite
run: hurl --test --variable base_url=http://127.0.0.1:3000 --report-junit reports/junit.xml tests/
- name: Archive the reports
if: always()
run: install -d /srv/api-tests/reports/$GITHUB_SHA && cp -r reports/. /srv/api-tests/reports/$GITHUB_SHA/
- name: Stop the mock
if: always()
run: docker compose downArchive step मधील if: always() महत्त्वाचे आहे. ते नसल्यास test run अयशस्वी झाल्यावर copy टप्पा वगळला जातो. त्यामुळे तुम्हाला वाचायचा असलेला reportच गमावला जातो. Copy workspace च्या बाहेर करणेही आवश्यक आहे. पुढील job सुरू होण्यापूर्वी runner workspace साफ करतो आणि reports देखील त्यासोबत हटवले जातात.
परिणाम जतन करा, केवळ शेवटची run नाही
प्रत्येक commit साठी एक JUnit XML फाइल एकाच प्रश्नाचे उत्तर देते: ती यशस्वी झाली का. Endpoint कधी धीमा होऊ लागला हे त्यातून कळत नाही, कारण तुम्ही त्या फाइल्स उघडणे थांबवल्यावर त्या वाचणारी कोणतीही प्रक्रिया राहत नाही. Trend पाहण्यासाठी, प्रत्येक run साठी त्याच box वरील छोट्या database मध्ये एक row जोडा. Commit SHA, file name, pass count, fail count आणि duration ठेवणारी एकच table पुरेशी आहे. ती ठेवण्यासाठी VPS वरील production मधील SQLite हा योग्य पर्याय आहे: एक file, कोणतीही server process नाही आणि तुम्ही आधीच घेत असलेल्या backup सोबत संपूर्ण history जतन होते. JUnit XML ऐवजी Hurl चे --report-json output parse करा, कारण दोन्हीपैकी ते machine-readable format आहे.
कंटेनर पुन्हा तयार केल्यानंतर काय टिकून राहिले पाहिजे
Mock definitions आणि test suites हा source code आहे. ते संबंधित service च्या repository मध्ये ठेवले पाहिजेत. Endpoint मध्ये बदल करणाऱ्या pull request सोबतच त्यातही बदल केला पाहिजे. Web UI मध्ये संपादित केलेला stub किंवा runtime मध्ये MockServer च्या REST API द्वारे पाठवलेली expectation फक्त त्या container च्या memory मध्ये किंवा त्या tool च्या database मध्ये अस्तित्वात असते. docker compose down चालवल्यावर ती नाहीशी होते. चुकीच्या कारणामुळे एखादी test पास होईपर्यंत हे कोणाच्याही लक्षात येत नाही. तुमच्या repositories तुमच्या स्वतःच्या hardware वरही चालत असतील, तर self-hosted git server fixtures आणि service यांना एकाच trust boundary मध्ये ठेवतो.
आता व्यावहारिक नियम पाहू. Image tags pin करा. कारण latest तुमच्या repository मध्ये कोणताही बदल न करता तुमचा mock requests शी जुळण्याची पद्धत बदलू शकते. अशा failure चे मूळ कारण शोधणे अत्यंत कठीण असते. Tool ला stub directories मध्ये लिहिण्याची गरज नसल्यास त्या read only mount करा. Mock चे stubs named Docker volume मध्ये कधीही ठेवू नका. तसे केल्यास volume हा source of truth बनतो आणि git मधील प्रत शांतपणे चुकीची ठरते.
आणखी एक महत्त्वाची गोष्ट आहे. Proxy द्वारे real traffic record करून stubs तयार करत असाल, तर commit करण्यापूर्वी प्रत्येक generated file वाचा. Recording मध्ये upstream ने परत पाठवलेली माहिती जशीच्या तशी असते. त्यात bearer tokens आणि customer email addresses यांचा समावेश असू शकतो. ते commit केल्यास ही माहिती तुमच्या repository मध्ये कायमची साठते, कारण git deleted content देखील history मध्ये ठेवते.
FAQ
API mock server आणि API test runner यांच्यात काय फरक आहे?
Mock server विनंत्यांना प्रतिसाद देतो. CI मधून ज्या dependency ला कॉल करता येत नाही, तिच्या ऐवजी तो वापरला जातो आणि तो कधीही pass किंवा fail अहवाल देत नाही. API test runner तुमच्या स्वतःच्या सेवेवर विनंत्या पाठवतो, प्रतिसादांवर assertions करतो, एका कॉलमधील मूल्ये पुढील कॉलमध्ये वापरतो आणि assertion अयशस्वी झाल्यास non zero exit होतो. दोन्ही वेगवेगळ्या समस्या सोडवतात. त्यामुळे सामान्य रचनेत दोन्ही एकाच वेळी चालतात: runner तुमच्या सेवेवर कॉल करतो आणि तुमची सेवा mock ला कॉल करते.
Hosted CI runner मधून internal API ची चाचणी करू शकतो का?
ते सार्वजनिकपणे उघड केल्याशिवाय शक्य नाही. Hosted runner तुमच्या network च्या बाहेर असतो. त्यामुळे private address वर bind केलेल्या सेवेपर्यंत तो पोहोचू शकत नाही. तुमच्याकडे API सार्वजनिक करणे, tunnel चालवणे किंवा public staging copy राखणे हे पर्याय आहेत. प्रत्येक पर्यायामुळे अपयशी ठरू शकणारी किंवा माहिती गळती करू शकणारी आणखी एक system जोडली जाते. त्याच private network वरील runner सेवेवर थेट कॉल करू शकतो. हे काम self host करण्याचे मुख्य व्यावहारिक कारण हेच आहे.
Mock stubs आणि API test suites कुठे ठेवावेत?
ते git मध्ये, ज्या service चे वर्णन करतात तिच्या शेजारी ठेवा. WireMock च्या mappings/ directory, Mockoon च्या data file, Hurl files आणि Bruno च्या .bru folder सारख्या files म्हणून definitions साठवणाऱ्या tools मुळे code review करता येते आणि कोणताही अतिरिक्त खर्च न करता container rebuild करता येतो. Database किंवा web UI मध्ये definitions साठवणाऱ्या tools साठी backup plan आणि export step आवश्यक असतो. Container आधीच नाहीसे झाल्यावरच लोकांना export करायचे आठवते.
Stub योग्य दिसत असताना माझा mock 404 का परत करतो?
WireMock stub फक्त exact match झाल्यावर serve करतो. जुळणारी विनंती नसल्यास 404 मिळते. त्याच्या body ची सुरुवात Request was not matched ने होते. त्यानंतर सर्वात जवळच्या stub विरुद्धचा diff दिला जातो. या diff मध्ये कोणते field वेगळे आहे ते नमूद केलेले असते. सामान्य कारणांमध्ये path च्या शेवटी असलेला slash, stub ला आवश्यक असलेला पण client ने न पाठवलेला Content-Type header, variable segment साठी stub ला urlPathPattern आवश्यक असताना वापरलेले urlPath, आणि payload शी जुळत नसलेला body matcher यांचा समावेश होतो. विनंती mock पर्यंत पोहोचली आहे का हे प्रथम तपासण्यासाठी /__admin/requests तपासा.
Staging environment असल्यासही मला mocks आवश्यक आहेत का?
होय, दोन कारणांसाठी. तुमच्या नियंत्रणाबाहेरील upstream ची staging copy बंद पडू शकते आणि ती तुम्हाला rate limit करू शकते. त्यामुळे तुमच्या code शी संबंध नसलेल्या कारणांमुळे suite अयशस्वी होऊ शकते. तसेच चाचणीसाठी सर्वाधिक आवश्यक असलेले responses ती तयार करू शकत नाही, जसे declined card किंवा gateway timeout. Mock हे responses मागणीनुसार local network speed ने परत करतो. त्यामुळे sandbox विरुद्ध काही मिनिटे घेणारी suite काही सेकंदांत पूर्ण होते. Release करण्यापूर्वीच्या अंतिम तपासणीसाठी staging ठेवा आणि CI मध्ये mocks वापरा.