معرفی
هنگام نوشتن تستها یا بررسی تستهایی که دیگران نوشتهاند، درک ساختار چهار مرحلهای تستها میتواند بسیار مفید باشد. این مراحل عبارتاند از:
Setup (راهاندازی)
Exercise (اجرا)
Assertion (بررسی)
Teardown (پاکسازی)
بیایید این چهار مرحله را با مثالی بررسی کنیم.
مثال
فرض کنیم یک اپلیکیشن داریم که لیستی از کاربران را مدیریت میکند. تنها کاربران فعال اجازه دارند پیام دریافت کنند. بنابراین باید بررسی کنیم که اگر کاربری غیرفعال باشد، امکان دریافت پیام برای او وجود نداشته باشد.
مراحل تست:
Setup: ایجاد یک کاربر در دیتابیس
Exercise: تغییر وضعیت کاربر به غیرفعال
Assertion: بررسی اینکه کاربر قابلیت دریافت پیام ندارد
Teardown: حذف رکورد کاربر از دیتابیس
توضیح هر فاز
1. Setup (راهاندازی)
در این مرحله، دادههای مورد نیاز برای اجرای تست ایجاد میشوند. در مثال بالا، ایجاد رکورد کاربر در دیتابیس بخشی از setup است. در تستهای پیچیدهتر، ممکن است چندین رکورد و ارتباط میان آنها تعریف شود.
2. Exercise (اجرا)
در این مرحله، ویژگی یا رفتاری از سیستم که قرار است تست شود، اجرا میگردد. در مثال بالا، تغییر وضعیت فعال به غیرفعال برای کاربر انجام میشود.
نکته: گاهی مرز بین setup و exercise واضح نیست، بهویژه در تستهای سطح پایین. مثلاً ممکن است تغییر وضعیت کاربر به غیرفعال نیز بخشی از setup تلقی شود، اگر هدف تست صرفاً بررسی خروجی یک تابع باشد.
3. Assertion (بررسی)
این مرحله، اصل ماجرای تست است؛ یعنی بررسی صحت خروجی یا وضعیت. تمامی مراحل قبلی، فقط زمینهسازی برای این بررسی هستند.
4. Teardown (پاکسازی)
تستها باید محیط اجرای خود را تمیز کنند. در غیر این صورت، دادهها یا وضعیتها روی تستهای بعدی تأثیر گذاشته و باعث عدم قطعیت (non-determinism) در نتایج میشوند.
در برخی فریمورکها مثل PHPUnit، مکانیزمهایی مثل transaction rollbacks یا ابزارهایی مثل database refresh باعث میشوند نیاز به teardown دستی نباشد، اما در برخی موارد پیچیدهتر، همچنان پاکسازی ضروری است.
مثال در PHP
use PHPUnit\Framework\TestCase;
use App\Models\User;
class UserTest extends TestCase
{
protected User $user;
protected function setUp(): void
{
parent::setUp();
// setup
$this->user = User::create([
'email' => 'test@example.com',
'active' => true,
]);
}
public function test_inactive_user_is_not_messageable(): void
{
// exercise
$this->user->update(['active' => false]);
// assertion
$this->assertFalse($this->user->isMessageable());
}
protected function tearDown(): void
{
// teardown
$this->user->delete();
parent::tearDown();
}
}
برداشت نهایی
درک این چهار مرحله میتواند نوشتن تست را سادهتر کند، بهخصوص زمانی که نمیدانید از کجا شروع کنید. گفتن "بیایید مرحله setup را بنویسیم" بسیار سادهتر از این است که بگوییم "بیایید یک تست کامل بنویسیم".
همچنین این درک به خوانایی و فهم سریعتر تستهای موجود نیز کمک میکند.