تست API یکی از مؤثرترین سطوح تست اتوماتیک است. بر خلاف تست UI که به رندر شدن مرورگر وابسته است، تست API مستقیماً با منطق کسبوکار سروکار دارد — سریعتر اجرا میشود، کمتر میشکند، و مشکلات را در لایهای پیدا میکند که رفع آنها ارزانتر است.
اگر از نرم افزار TestComplete برای تست رابط کاربری استفاده میکنید، احتمالاً میدانید که این ابزار قابلیتهای تست API هم دارد — اما خیلی از تیمها از آن استفاده نمیکنند چون مستندات فارسی کمی در این زمینه وجود دارد.
این مقاله آن خلأ را پر میکند. گامبهگام یاد میگیرید که با TestComplete چطور یک REST API را تست کنید، پاسخ JSON را اعتبارسنجی کنید، تست را data-driven کنید، و در آخر به pipeline CI/CD وصل کنید.
چرا تست API در TestComplete؟
قبل از شروع، یک سوال منطقی: وقتی ابزارهایی مثل Postman یا Rest-Assured برای تست API وجود دارند، چرا از TestComplete استفاده کنیم؟
دو دلیل اصلی:
یکپارچگی: اگر تیم شما از TestComplete برای تست UI هم استفاده میکند، نگه داشتن تستهای API در همان ابزار یعنی یک گزارش یکپارچه، یک pipeline، و یک مکان برای مدیریت همه تستها. دیگر لازم نیست بین Postman، TestComplete، و گزارشهای جداگانه سوئیچ کنید.
End-to-end testing واقعی: میتوانید تستهایی بنویسید که ابتدا از طریق API یک رکورد میسازند، سپس در رابط کاربری آن را تأیید میکنند — همه در یک اسکریپت، با یک نتیجه.
پیشنیازها
برای دنبال کردن این آموزش نیاز دارید به:
- TestComplete 15 یا بالاتر نصبشده با لایسنس فعال (راهنمای خرید لایسنس)
- آشنایی پایه با مفهوم REST API — میدانید HTTP Request و Response چیست
- آشنایی مقدماتی با Python یا JavaScript (برای بخشهای پیشرفتهتر)
سناریوی این آموزش: API فروشگاه آنلاین
برای این آموزش از یک API فرضی فروشگاه آنلاین استفاده میکنیم — همان آرینشاپی که در آموزش تست اتوماتیک رابط کاربری با آن آشنا شدیم.
این API endpoints را پوشش میدهیم:
| Endpoint | Method | کاربرد |
|---|---|---|
/api/products |
GET | لیست محصولات |
/api/products/{id} |
GET | جزئیات یک محصول |
/api/cart |
POST | افزودن به سبد خرید |
/api/orders |
POST | ثبت سفارش |
/api/orders/{id} |
GET | وضعیت سفارش |
💬 برای دریافت قیمت و مشاوره رایگان → همین الان در تلگرام پیام دهید — پاسخ در کمتر از چند ساعت
گام اول: ایجاد پروژه API Test در TestComplete
TestComplete دو رویکرد برای تست API دارد:
۱. HTTP Request object — در اسکریپت Python/JS مستقیماً HTTP call میزنید ۲. Web Services module — برای SOAP/WSDL، رابط بصری دارد
در این آموزش از رویکرد اول استفاده میکنیم چون انعطافپذیرتر است و برای REST مناسبتر.
یک پروژه Script جدید بسازید:
- TestComplete را باز کنید
- از منوی File گزینه New Project را انتخاب کنید
- نام پروژه را
ArinShopApiTestsبگذارید - زبان را Python انتخاب کنید
- روی Finish کلیک کنید
در Project Explorer، روی Script کلیک راست کنید و یک Unit جدید به نام ProductApiTests اضافه کنید.
گام دوم: اولین تست GET — دریافت لیست محصولات
سادهترین تست ممکن: فراخوانی endpoint لیست محصولات و بررسی اینکه پاسخ معتبر است.
def Test_GetProductList():
# ساخت HTTP request
url = "https://api.arinshop.example.com/api/products"
httpRequest = TestComplete.CreateObject("TestComplete.HTTPRequest")
httpRequest.Method = "GET"
httpRequest.URL = url
httpRequest.AddHeader("Accept", "application/json")
httpRequest.AddHeader("Authorization", "Bearer " + GetAuthToken())
# ارسال درخواست
response = httpRequest.Send()
# اعتبارسنجی status code
if response.StatusCode != 200:
Log.Error("Status code نادرست: " + str(response.StatusCode))
return
Log.Message("✓ Status 200 OK")
# اعتبارسنجی Content-Type
contentType = response.GetHeader("Content-Type")
if "application/json" not in contentType:
Log.Error("Content-Type اشتباه است: " + contentType)
return
Log.Message("✓ Content-Type صحیح است")
# parse کردن JSON
import json
body = json.loads(response.Body)
# بررسی اینکه پاسخ یک لیست است
if not isinstance(body, list):
Log.Error("پاسخ باید آرایه باشد")
return
# بررسی اینکه حداقل یک محصول وجود دارد
if len(body) == 0:
Log.Error("لیست محصولات خالی است")
return
Log.Message("✓ تعداد محصولات دریافتشده: " + str(len(body)))
# بررسی ساختار اولین آیتم
first_product = body[0]
required_fields = ["id", "name", "price", "stock"]
for field in required_fields:
if field not in first_product:
Log.Error("فیلد '" + field + "' در پاسخ وجود ندارد")
else:
Log.Message("✓ فیلد '" + field + "' موجود است")
این تست چهار چیز را بررسی میکند: status code، content-type، ساختار کلی پاسخ، و وجود فیلدهای ضروری. هیچکدام از اینها با تست UI قابل تست نیستند — باید مستقیماً API را بزنید.
گام سوم: تابع کمکی برای Authentication
اکثر API های واقعی نیاز به احراز هویت دارند. یک تابع مشترک برای گرفتن token بسازید تا در همه تستها استفاده شود:
def GetAuthToken():
"""
Login میکند و access token برمیگرداند.
نتیجه را در یک متغیر project ذخیره میکند
تا در هر test session فقط یک بار فراخوانی شود.
"""
# اگر قبلاً token گرفتهایم، همان را برگردان
cached_token = Project.Variables.AuthToken
if cached_token != "":
return cached_token
httpRequest = TestComplete.CreateObject("TestComplete.HTTPRequest")
httpRequest.Method = "POST"
httpRequest.URL = "https://api.arinshop.example.com/api/auth/login"
httpRequest.AddHeader("Content-Type", "application/json")
import json
credentials = json.dumps({
"username": Project.Variables.TestUsername,
"password": Project.Variables.TestPassword
})
httpRequest.Body = credentials
response = httpRequest.Send()
if response.StatusCode != 200:
Log.Error("Login ناموفق بود. Status: " + str(response.StatusCode))
return ""
body = json.loads(response.Body)
token = body.get("access_token", "")
# ذخیره در Project Variable برای استفاده مجدد
Project.Variables.AuthToken = token
Log.Message("✓ Authentication موفق")
return token
نکته مهم: username و password را هرگز مستقیم در کد ننویسید. از Project Variables استفاده کنید — میتوانید آنها را encrypted ذخیره کنید و در محیط CI/CD از environment variable بخوانید.
گام چهارم: تست POST — ثبت سفارش
تستهای POST پیچیدهتر هستند چون باید body درخواست را بسازید و پاسخ ایجاد رکورد جدید را اعتبارسنجی کنید:
def Test_CreateOrder():
import json
# آمادهسازی داده سفارش
order_payload = {
"items": [
{"product_id": 101, "quantity": 2},
{"product_id": 205, "quantity": 1}
],
"shipping_address": {
"city": "تهران",
"street": "خیابان آزادی",
"postal_code": "1234567890"
},
"payment_method": "wallet"
}
httpRequest = TestComplete.CreateObject("TestComplete.HTTPRequest")
httpRequest.Method = "POST"
httpRequest.URL = "https://api.arinshop.example.com/api/orders"
httpRequest.AddHeader("Content-Type", "application/json")
httpRequest.AddHeader("Authorization", "Bearer " + GetAuthToken())
httpRequest.Body = json.dumps(order_payload, ensure_ascii=False)
response = httpRequest.Send()
# ۲۰۱ Created انتظار داریم، نه ۲۰۰
aqVerification.CheckEqual(
response.StatusCode,
201,
"Status code ثبت سفارش باید 201 باشد"
)
body = json.loads(response.Body)
# بررسی وجود order_id در پاسخ
aqVerification.CheckNotEqual(
body.get("order_id", None),
None,
"پاسخ باید order_id داشته باشد"
)
# بررسی status اولیه سفارش
aqVerification.CheckEqual(
body.get("status"),
"pending",
"سفارش جدید باید status = pending داشته باشد"
)
# ذخیره order_id برای استفاده در تست بعدی
Project.Variables.LastOrderId = str(body["order_id"])
Log.Message("✓ سفارش با ID " + str(body["order_id"]) + " ثبت شد")
return body["order_id"]
💬 برای دریافت قیمت و مشاوره رایگان → همین الان در تلگرام پیام دهید — پاسخ در کمتر از چند ساعت
گام پنجم: زنجیره کردن تستها — End-to-End API Flow
قدرت واقعی تست API وقتی ظاهر میشود که تستها را به هم زنجیر میکنید — درست مثل یک کاربر واقعی که چند مرحله را پشت سر هم انجام میدهد:
def Test_FullOrderFlow():
"""
یک flow کامل را تست میکند:
۱. دریافت لیست محصولات
۲. بررسی موجودی یک محصول خاص
۳. ثبت سفارش
۴. تأیید وضعیت سفارش
"""
import json
# ---- مرحله ۱: دریافت محصولات ----
Log.AppendFolder("مرحله ۱: دریافت لیست محصولات")
req = TestComplete.CreateObject("TestComplete.HTTPRequest")
req.Method = "GET"
req.URL = "https://api.arinshop.example.com/api/products?category=shoes"
req.AddHeader("Authorization", "Bearer " + GetAuthToken())
resp = req.Send()
aqVerification.CheckEqual(resp.StatusCode, 200, "دریافت محصولات")
products = json.loads(resp.Body)
first_available = next(
(p for p in products if p["stock"] > 0),
None
)
if first_available is None:
Log.Error("هیچ محصول موجودی یافت نشد")
return
product_id = first_available["id"]
Log.Message("✓ محصول انتخابشده: " + first_available["name"])
Log.PopLogFolder()
# ---- مرحله ۲: بررسی جزئیات محصول ----
Log.AppendFolder("مرحله ۲: بررسی جزئیات محصول")
req2 = TestComplete.CreateObject("TestComplete.HTTPRequest")
req2.Method = "GET"
req2.URL = "https://api.arinshop.example.com/api/products/" + str(product_id)
req2.AddHeader("Authorization", "Bearer " + GetAuthToken())
resp2 = req2.Send()
product_detail = json.loads(resp2.Body)
aqVerification.CheckEqual(
product_detail["id"],
product_id,
"ID محصول در جزئیات صحیح است"
)
aqVerification.CheckNotEqual(
product_detail.get("price"),
None,
"قیمت محصول وجود دارد"
)
Log.PopLogFolder()
# ---- مرحله ۳: ثبت سفارش ----
Log.AppendFolder("مرحله ۳: ثبت سفارش")
order_id = Test_CreateOrder()
if order_id is None:
Log.Error("ثبت سفارش ناموفق بود — flow متوقف شد")
return
Log.PopLogFolder()
# ---- مرحله ۴: بررسی وضعیت سفارش ----
Log.AppendFolder("مرحله ۴: بررسی وضعیت سفارش")
req4 = TestComplete.CreateObject("TestComplete.HTTPRequest")
req4.Method = "GET"
req4.URL = "https://api.arinshop.example.com/api/orders/" + str(order_id)
req4.AddHeader("Authorization", "Bearer " + GetAuthToken())
resp4 = req4.Send()
order = json.loads(resp4.Body)
aqVerification.CheckEqual(resp4.StatusCode, 200, "دریافت وضعیت سفارش")
aqVerification.CheckEqual(
order["id"],
order_id,
"ID سفارش در پاسخ صحیح است"
)
valid_statuses = ["pending", "confirmed", "processing"]
if order["status"] not in valid_statuses:
Log.Error("وضعیت سفارش نامعتبر است: " + order["status"])
else:
Log.Message("✓ وضعیت سفارش: " + order["status"])
Log.PopLogFolder()
Log.Message("✓ Full order flow با موفقیت تست شد")
استفاده از Log.AppendFolder و Log.PopLogFolder باعث میشود گزارش TestComplete ساختار تودرتو داشته باشد — هر مرحله جداگانه نمایش داده میشود و فهمیدن اینکه کجا مشکل پیش آمده آسانتر است.
گام ششم: تست خطاها — سناریوهای منفی
تست کردن فقط happy path کافی نیست. API باید برای ورودیهای اشتباه هم رفتار صحیح داشته باشد:
def Test_ErrorScenarios():
import json
# ---- تست ۱: درخواست بدون Authentication ----
Log.AppendFolder("تست بدون token")
req = TestComplete.CreateObject("TestComplete.HTTPRequest")
req.Method = "GET"
req.URL = "https://api.arinshop.example.com/api/orders"
# عمداً header Authorization اضافه نمیکنیم
resp = req.Send()
aqVerification.CheckEqual(
resp.StatusCode,
401,
"بدون token باید 401 Unauthorized برگردد"
)
Log.PopLogFolder()
# ---- تست ۲: ID محصول نامعتبر ----
Log.AppendFolder("تست ID نامعتبر")
req2 = TestComplete.CreateObject("TestComplete.HTTPRequest")
req2.Method = "GET"
req2.URL = "https://api.arinshop.example.com/api/products/99999999"
req2.AddHeader("Authorization", "Bearer " + GetAuthToken())
resp2 = req2.Send()
aqVerification.CheckEqual(
resp2.StatusCode,
404,
"محصول ناموجود باید 404 برگرداند"
)
Log.PopLogFolder()
# ---- تست ۳: body ناقص در POST ----
Log.AppendFolder("تست body ناقص")
req3 = TestComplete.CreateObject("TestComplete.HTTPRequest")
req3.Method = "POST"
req3.URL = "https://api.arinshop.example.com/api/orders"
req3.AddHeader("Content-Type", "application/json")
req3.AddHeader("Authorization", "Bearer " + GetAuthToken())
req3.Body = json.dumps({"items": []}) # items خالی
resp3 = req3.Send()
aqVerification.CheckEqual(
resp3.StatusCode,
400,
"سبد خرید خالی باید 400 Bad Request برگرداند"
)
# بررسی پیام خطا در body پاسخ
error_body = json.loads(resp3.Body)
if "error" not in error_body and "message" not in error_body:
Log.Warning("پاسخ خطا باید فیلد 'error' یا 'message' داشته باشد")
Log.PopLogFolder()
گام هفتم: Data-Driven API Testing
همان منطق data-driven که در تست رابط کاربری استفاده کردیم، برای API هم کار میکند. یک فایل Excel با سناریوهای مختلف میسازیم:
| product_id | quantity | expected_status | expected_http |
|---|---|---|---|
| 101 | 1 | pending | 201 |
| 202 | 5 | pending | 201 |
| 303 | 0 | — | 400 |
| 99999 | 1 | — | 404 |
def Test_DataDriven_OrderCreation():
import json
# اتصال به فایل Excel
DDT.ExcelDriver(
"C:\\TestData\\order_scenarios.xlsx",
"Sheet1",
True # first row = header
)
while not DDT.CurrentDriver.EOF():
product_id = int(DDT.CurrentDriver.Value("product_id"))
quantity = int(DDT.CurrentDriver.Value("quantity"))
expected_http = int(DDT.CurrentDriver.Value("expected_http"))
# ساخت و ارسال درخواست
req = TestComplete.CreateObject("TestComplete.HTTPRequest")
req.Method = "POST"
req.URL = "https://api.arinshop.example.com/api/orders"
req.AddHeader("Content-Type", "application/json")
req.AddHeader("Authorization", "Bearer " + GetAuthToken())
req.Body = json.dumps({
"items": [{"product_id": product_id, "quantity": quantity}],
"payment_method": "wallet"
})
resp = req.Send()
# اعتبارسنجی
label = "product_id=" + str(product_id) + ", qty=" + str(quantity)
aqVerification.CheckEqual(
resp.StatusCode,
expected_http,
"HTTP status برای سناریو: " + label
)
DDT.CurrentDriver.Next()
DDT.CurrentDriver.Close()
با این روش، هر ردیف Excel یک تست مستقل میشود. اضافه کردن سناریوی جدید فقط یعنی اضافه کردن یک ردیف — بدون تغییر کد.
گام هشتم: تست SOAP Web Service
اگر با سیستمهای قدیمیتر مثل سیستمهای بانکی یا ERP کار میکنید، احتمالاً با SOAP روبرو میشوید. TestComplete برای این کار یک رابط بصری دارد:
- در Project Explorer روی پروژه کلیک راست کنید
- Add → New Item → Web Service را انتخاب کنید
- آدرس WSDL سرویس را وارد کنید
- TestComplete به صورت خودکار تمام متدها را import میکند
بعد از import، میتوانید متدها را مستقیماً از اسکریپت فراخوانی کنید:
def Test_SoapPaymentService():
# فراخوانی متد SOAP
ws = WebServices.PaymentService
result = ws.ProcessPayment(
OrderId="ORD-2025-001",
Amount=850000,
Currency="IRR",
PaymentMethod="BankTransfer"
)
# اعتبارسنجی پاسخ SOAP
aqVerification.CheckEqual(
result.StatusCode,
"SUCCESS",
"پرداخت باید موفق باشد"
)
aqVerification.CheckNotEqual(
result.TransactionId,
"",
"TransactionId نباید خالی باشد"
)
Log.Message("✓ پرداخت موفق — TransactionId: " + result.TransactionId)
گام نهم: یکپارچگی با CI/CD
همانطور که در مقاله اصلی TestComplete توضیح داده شده، اجرای تست از command line یک دستور ساده است. برای یک pipeline که فقط تستهای API را اجرا میکند (بدون نیاز به باز کردن مرورگر)، میتوانید TestComplete را در حالت headless اجرا کنید.
نمونه .gitlab-ci.yml برای تست API:
stages:
- api-test
- ui-test
api-regression:
stage: api-test
script:
- |
"C:\Program Files\SmartBear\TestComplete 15\Bin\TestComplete.exe"
"ArinShopApiTests\ArinShopApiTests.pjs"
/run /TestItem:"ApiTests"
/exit /SilentMode
/ExportLog:"TestResults\api-results.xml"
artifacts:
reports:
junit: TestResults/api-results.xml
variables:
TC_TEST_USERNAME: $TEST_API_USERNAME
TC_TEST_PASSWORD: $TEST_API_PASSWORD
only:
- main
- develop
نکته مهم: username و password را در pipeline به عنوان CI/CD Variables تعریف کنید و از environment variable در اسکریپت TestComplete بخوانید — نه hardcode در فایل پروژه.
گام دهم: گزارشگیری و نمونه خروجی
بعد از اجرا، TestComplete یک گزارش کامل میسازد. برای یک suite تست API، خروجی چیزی شبیه به این است:
| نام تست | نتیجه | مدت زمان | جزئیات |
|---|---|---|---|
| Test_GetProductList | ✓ Pass | ۰.۳ ثانیه | ۴۸ محصول دریافت شد |
| Test_CreateOrder | ✓ Pass | ۰.۸ ثانیه | order_id: 7842 |
| Test_FullOrderFlow | ✓ Pass | ۱.۹ ثانیه | ۴ مرحله موفق |
| Test_ErrorScenarios | ✓ Pass | ۰.۶ ثانیه | ۳ سناریوی خطا تأیید شد |
| Test_DataDriven (×4) | ✓ Pass | ۱.۲ ثانیه | ۴ از ۴ سناریو موفق |
توجه کنید تستهای API چقدر سریعتر از تستهای UI اجرا میشوند — زیرا نیازی به render مرورگر ندارند. یک suite ۵۰ تستی API معمولاً در کمتر از ۲ دقیقه تمام میشود.
💬 برای دریافت قیمت و مشاوره رایگان → همین الان در تلگرام پیام دهید — پاسخ در کمتر از چند ساعت
بهترین شیوهها
تستهای API را از UI جدا نگه دارید
در TestComplete، تستهای API و UI را در TestItems جداگانه سازماندهی کنید. این اجازه میدهد در pipeline آنها را موازی یا به ترتیب خاصی اجرا کنید.
هرگز token یا password را در کد ننویسید
از Project Variables با نوع Encrypted برای اطلاعات حساس استفاده کنید. در CI/CD از environment variables بخوانید:
import os
username = os.environ.get("TC_TEST_USERNAME", "default_test_user")
برای هر تست یک teardown بنویسید
اگر تست شما دادهای در دیتابیس میسازد (مثل سفارش)، بعد از تست آن را پاک کنید تا تستهای بعدی با دادههای کثیف روبرو نشوند:
def Teardown_DeleteTestOrder(order_id):
req = TestComplete.CreateObject("TestComplete.HTTPRequest")
req.Method = "DELETE"
req.URL = "https://api.arinshop.example.com/api/test/orders/" + str(order_id)
req.AddHeader("Authorization", "Bearer " + GetAdminToken())
req.Send()
response time را هم تست کنید
SLA یک API فقط correctness نیست — سرعت هم مهم است:
import time
start = time.time()
resp = req.Send()
elapsed = time.time() - start
if elapsed > 2.0:
Log.Warning("API کند است: " + str(round(elapsed, 2)) + " ثانیه")
else:
Log.Message("✓ Response time: " + str(round(elapsed, 2)) + " ثانیه")
جمعبندی
تست API با TestComplete یک مزیت بزرگ دارد که با هیچ ابزار جداگانهای نمیتوانید تکرار کنید: یکپارچگی کامل با تستهای UI در یک پروژه، یک گزارش، و یک pipeline.
اگر تیم شما از نرم افزار TestComplete برای تست رابط کاربری استفاده میکند و هنوز API را با Postman یا ابزار جداگانه تست میکنید، یک مرحله ساده میتواند همه چیز را یکپارچه کند.
برای خرید لایسنس TestComplete یا دریافت مشاوره رایگان درباره راهاندازی تست API در پروژه خودتان، از طریق تلگرام با ما در تماس باشید.
سوالات متداول
سوال: آیا میتوان با TestComplete GraphQL را هم تست کرد؟
بله. GraphQL روی HTTP/HTTPS کار میکند و TestComplete میتواند هر درخواست HTTP ارسال کند. فقط باید Content-Type: application/json تنظیم کنید، query را به عنوان JSON body ارسال کنید، و پاسخ JSON را parse کنید. تفاوتی با REST ندارد.
سوال: آیا TestComplete میتواند WebSocket را تست کند؟
به صورت مستقیم خیر. تست WebSocket در TestComplete نیاز به workaround دارد — معمولاً از طریق JavaScript injected در مرورگر. برای تست جدی WebSocket، ابزارهای تخصصیتر مثل k6 یا Artillery مناسبترند.
سوال: چطور میتوانم تست API را با تست UI در یک سناریو ترکیب کنم؟
در یک script unit، ابتدا API call بزنید تا داده بسازید، سپس از Aliases برای کنترل رابط کاربری استفاده کنید. TestComplete هر دو API را در اسکریپت یکسانی در دسترس میگذارد.
سوال: آیا میتوان response schema را به صورت خودکار validate کرد؟
بله، با import کتابخانه jsonschema در Python میتوانید schema validation کامل انجام دهید. از آنجا که TestComplete از Python استفاده میکند، هر کتابخانهای که با pip قابل نصب باشد در دسترس است.
سوال: تفاوت تست API در TestComplete با Postman چیست؟
Postman برای exploratory testing و مستندسازی API عالی است. TestComplete برای regression testing automation که در CI/CD اجرا میشود و با تستهای UI یکپارچه است. هر دو جای خود را دارند — اما برای تست خودکار تکرارشونده، TestComplete قویتر است.
خرید لایسنس اورجینال — مشاوره رایگان
قیمت دقیق بر اساس نسخه و تعداد کاربر متفاوت است. برای دریافت قیمت و راهنمایی رایگان با ما در تلگرام پیام دهید.
|
✓
+۲۰ سال تجربه
متخصصان مهندسی نرمافزار با سابقه بلندمدت
|
⚡
تحویل زیر ۲۴ ساعت
لایسنس شما ظرف یک روز کاری ارسال میشود
|
↩
ضمانت بازگشت وجه
در صورت عدم کارایی، مبلغ را کامل برمیگردانیم
|
پاسخ معمولاً در کمتر از چند ساعت — بدون پیشپرداخت برای مشاوره



