تست بدون سرور پیچیده نیست. فقط کمی تلاش می خواهد
آزمایش برنامه های بدون سرور به دلیل معماری منحصر به فرد آنها می تواند پیچیده به نظر برسد، به خصوص اگر شما نسبتاً جدید هستید. اما، البته، شنیدن اینکه محاسبات بدون سرور نیاز به یک طرز فکر جدید دارد کمکی نمیکند، زیرا نحوه ساخت و استقرار برنامهها را تغییر میدهد.
من نمیتوانم کاملاً با این گفته موافق باشم زیرا حتی با معماری سنتی مبتنی بر سرور، که باید کنترل کاملی بر محیطی که کدم در آن اجرا میشود داشته باشم، اجرای کامل آن در محیط محلی من همچنان پیچیده است. من هنوز پیکربندی های خسته کننده و نرم افزارهای مختلف را برای نصب برای اجرای کل برنامه به یاد دارم.
تست بدون سرور پیچیده تر از تست سنتی نیست مگر اینکه پروژه Hello World را توسعه دهم. متفاوت است و از قوانین مختلفی پیروی می کند.
از آنجایی که ارائهدهنده ابر زیرساخت زیربنایی را مدیریت میکند، ایجاد مجدد همان محیطی که کد در آن اجرا میشود میتواند چالش برانگیز باشد. این می تواند منجر به مشکلات غیرمنتظره در هنگام استقرار کد در تولید شود. به عنوان مثال، یک برنامه معمولی بدون سرور میتواند از چند لامبدا و سرویسهای دیگر برای چسباندن آنها به هم تشکیل شود و به توسعهدهندگان نیاز دارد که از طرحهای آزمایشی یکپارچه سنتی منطبق شوند و دور شوند.
برای کاهش این چالش ها، توسعه دهندگان باید استراتژی های آزمایشی جدیدی را اتخاذ کنند که ویژگی های منحصر به فرد محاسبات بدون سرور را در نظر بگیرد. این ممکن است شامل استفاده از ابزارهای تست تخصصی، ایجاد قابلیتهای نظارت و گزارش بیشتر، و تکیه بیشتر بر خطوط لوله آزمایش و استقرار خودکار باشد.
صرف نظر از نوع پروژه، یک رویکرد و استراتژی عملی هنگام آزمایش یک برنامه کاربردی بدون سرور توزیع شده شامل دنبال کردن یک فرآیند واضح است.
استراتژی تست بدون سرور من به مراحل زیر تقسیم می شود:
-
تست های واحد
-
تست های جزء
-
تست های e2e
هدف آزمونهای واحد پوشش 100 درصدی منطق کسبوکار است که منطقی آن را اثبات میکند. با فرض یک ادعا برای هر آزمون، می توانم اطمینان حاصل کنم که هر خط کد به طور کامل تست شده است. به عنوان مثال، اگر کد حاوی دستور if باشد، یک تست واحد باید هر شاخه از دستور را پوشش دهد
1 await myService.doSomething();
2 const result = await myService.doSomethingElse();
3 if result?.items && something {
4 await myService2.doSomething();
5 return "ok";
6 }
7
8 return "ciao";
انتظار دارم موارد زیر را ببینم:
-
با بیان اینکه خط 1 با پارامترهای مورد انتظار در صورت وجود فراخوانی می شود
-
نتیجه صفر یا تعریف نشده است
-
result یک شی است، اما result.item تعریف نشده یا تهی است
-
result یک شی است و result.item یک آرایه خالی است
-
result یک شی است و result.item یک آرایه غیر خالی است، اما چیزی نادرست است
-
result یک شی است و result.item یک آرایه غیر خالی است و چیزی درست است
-
result یک شی است و result.item یک آرایه غیر خالی است و چیزی درست است و در صورت وجود، خط 4 را با پارامترهای مورد انتظار مشخص کنید.
هنگامی که در تست های واحد اطمینان بالایی وجود داشت، زمان آزمایش لامبدا و اتصالات آن فرا می رسد. من تمام زیرساخت هایم را در فضای ابری آزمایش می کنم زیرا تجربه واقعی به من می دهد. این به این دلیل است که در بیشتر مواقع، بسیاری از شبیهسازها نیاز به پیکربندی دارند یا برای برخی از سرویسها پشتیبانی نمیشوند و نیاز به سازش دارند. در نهایت، من همه چیز را در فضای ابری آزمایش میکنم تا زندگیام آسانتر شود.
بر اساس استراتژی تست بدون سرور من، اکنون موارد زیر را گذاشته ام:
-
تست های جزء
-
تست های e2e
برای هر دوی آنها، من از خیار و یک ظاهر تست استفاده می کنم
تست های مؤلفه و e2e:
تست مولفه شامل آزمایش عملکردهای فردی در انزوا کامل است.
تابعی که توسط یک پیام SQS راه اندازی می شود، پردازش هایی را انجام می دهد، DynamoDB را فراخوانی می کند و یک رویداد را با EventBridge منتشر می کند.
در حالی که جریان منطقی با تست های واحد آزمایش می شود
نقشهای IAM برای استفاده از سرویسهایی مانند DynamoDB یا EventBridge نیاز به تأیید دارند. به عنوان مثال، من باید تعیین کنم که آیا EventBridge یا SQS قانون یا فیلتر صحیحی دارد یا خیر.
با تست کامپوننت، برای مثال، لامبدا EventSourcing را با Test SQS خود تغییر میدهم و در رویداد EventBridge با هدف آزمایشی جدیدم مشترک میشوم. سپس، بر اساس قانون تجارت، می توانم پیام های SQS خاصی را به عنوان ورودی قرار دهم و رویداد را در هدف خروجی اثبات کنم.
خیار دارای قلاب های مشروط است، مثلاً دامنه های مختلفی دارد و همچنین در زمان های مختلف اجرا می شود.
کاری که می توانم قبل از شروع همه آزمایش انجام دهم:
-
جایگزینی لامبدا EventSourcing
-
ایجاد هدف جدید EventBridge
-
جایگزینی نقطه پایانی شخص ثالث با سرویس Mock من
همه اینها می تواند در داخل رخ دهد beforeAll
. این تابع یک بار قبل از تمام تستها در مجموعه آزمایشی اجرا میشود و برای راهاندازی محیط تست، راهاندازی خدمات و غیره عالی است.
من می توانم چیزی مشابه داشته باشم:
export abstract class Steps {
public hooks: StepDefinitions = () => {
beforeAll(async (): Promise<void> => {
jest.setTimeout(Wait.JEST_TIMEOUT);
require("custom-env")
.env(getEnvironmentVariable("CI_ENVIRONMENT_NAME"));
const initActions = [];
if (!getEnvironmentVariable("TEST_TAG") || ["@myservice", "@myservice2"].includes(getEnvironmentVariable("TEST_TAG"))) {
initActions.push(setSqsAsTrigger(functionName));
initActions.push(setSqsAsTarget(eventBridge));
initActions.push(setMockService(functionName));
...
}
await Promise.all(initActions);
});
}
}
روش setSqsAsTrigger
می تواند به همین سادگی باشد:
import Lambda, { CreateEventSourceMappingRequest, ListEventSourceMappingsResponse } from "aws-sdk/clients/lambda";
async function setSqsAsTrigger(functionName: string, sqsArn: string): Promise<void> {
// listEventSourceMapping to see if it exists or not
// CreateEventSourceMappingRequest
// Waiting for event source mapping to be enabled
}
در حالی که ممکن است کمی بیش از حد به نظر برسد، دستیابی به آن با برخی کدهای ماژولار ساده است. با وجود این، میتوانم خدمات ورودی و خروجی مؤلفه خود را بر اساس آزمایشی که اجرا میکنم به صورت پویا جایگزین کنم.
تستهای کامپوننت معمولاً برای تست e2e مفید هستند زیرا:
-
من دامنه آزمایش را محدود می کنم، به این معنی که آنها سریعتر اجرا می شوند.
-
میتوانم مواردی مانند زمانبندی، دستهبندی و سایر پارامترها را جایگزین کنم تا آزمایش را سریعتر انجام دهم.
-
من می توانم آنها را به طور خودکار در هر commit اجرا کنم.
با تستهای کامپوننت سبز و متصل به CI من، میتوانم در تولید مستقر شوم، سناریوهایی مانند استقرار مستمر (CD) را فعال کنم یا وقتی کارم را پشت سر بگذارم، زمان QA زیادی را تلف نکنم.
تفاوت با تست e2e چیست؟
در حالی که آنها بسیار شبیه به تست های کامپوننت هستند، در این مورد، من سرویس ها را بین میکروسرویس ها یا دسته بندی، قوانین یا تایم اوت تغییر نمی دهم.
در عوض، بر اساس قوانین کسب و کار برنامهام، ورودیهایی را در ابتدای زنجیره ایجاد میکنم و در انتهای آن منتظر خروجی میمانم، جایی که درخواست خود را تأیید و تأیید میکنم.
برای مثال، یک آزمایش میتواند برای چندین دقیقه اجرا شود، بنابراین مجموعه کلی ممکن است ساعتها طول بکشد و آن را برای استقرار سریع و مداوم نامناسب کند.
من این گزینه را برای تمسخر API شخص ثالث با استفاده از برچسب های منحصر به فرد و متغیرهای محیطی حفظ می کنم. این به این دلیل است که در حالی که رابط کاربری یک تیم/سرویس شخص ثالث را میدانم، نمیتوانم فقط برای اجرای آزمایشم به آنها برای راهاندازی سیستمشان یا در وضعیت سالم اعتماد کنم. بنابراین من در درجه اول با یک سرویس Mock (APIGW + DynamoDB) اجرا می کنم که در آن داده هایی را که انتظار دارم برگردانده شوند تنظیم می کنم. اگر در عوض، به دلایلی، نیاز به آزمایش وابستگی به تیمها/سرویسهای دیگر داشته باشم، زیرا رابط کاربری تغییر کرده است یا به دلایل دیگر، e2e را با برچسب منحصربهفرد یا متغیر محیطی فعال میکنم.
نتیجه
استراتژی بالا تا کنون به خوبی کار می کند. در ابتدا دارای یک منحنی تند است زیرا نیاز به تنظیم همه موارد دارد، اما در نهایت سرعت و پایداری برنامه را به شما میدهد و به شما اطمینان میدهد که در هر زمانی از سال منتشر کنید. امیدوارم که این مورد برای شما مفید واقع شده باشد و بتوانید از برخی از قطعات دوباره استفاده کنید و آنها را در استراتژی تست بدون سرور خود اعمال کنید.