واحد تست چیست و چگونه طراحی می‌شود

خلاصه
1404/09/19

واحد تست (Unit Test) نوعی تست نرم‌افزاری است که یک واحد (Unit) یا کامپوننت (Component) از نرم‌افزار را به صورت مجزا و مستقل از سایر قسمت‌ها تست می‌کند. هدف از واحد تست، اطمینان

واحد تست چیست و چگونه طراحی می‌شود

واحد تست (Unit Test) نوعی تست نرم‌افزاری است که یک واحد (Unit) یا کامپوننت (Component) از نرم‌افزار را به صورت مجزا و مستقل از سایر قسمت‌ها تست می‌کند. هدف از واحد تست، اطمینان از این است که هر واحد از کد به درستی کار می‌کند و مطابق با انتظارات عمل می‌کند. واحد تست‌ها معمولاً توسط توسعه‌دهندگان نوشته می‌شوند.

**هدف از واحد تست:**

* **تشخیص زودهنگام خطاها:** با تست کردن اجزای کوچک به صورت مجزا، می‌توان خطاها را زودتر در چرخه توسعه شناسایی و رفع کرد.
* **افزایش قابلیت اطمینان کد:** واحد تست‌ها با اطمینان از عملکرد صحیح هر واحد، به افزایش قابلیت اطمینان کلی نرم‌افزار کمک می‌کنند.
* **تسهیل Refactoring:** وقتی کد تغییر می‌کند (Refactor می‌شود)، واحد تست‌ها اطمینان می‌دهند که تغییرات، عملکرد موجود را خراب نمی‌کنند.
* **به عنوان مستندات:** واحد تست‌ها می‌توانند به عنوان مستنداتی زنده عمل کنند که نشان می‌دهند یک واحد کد چگونه باید کار کند.

**ویژگی‌های یک واحد تست خوب:**

* **سریع:** واحد تست‌ها باید سریع اجرا شوند تا زمان زیادی از توسعه‌دهندگان نگیرند.
* **تکرارپذیر (Repeatable):** یک واحد تست باید همیشه با یک ورودی مشخص، یک خروجی مشخص و قابل پیش‌بینی داشته باشد.
* **مستقل (Independent):** واحد تست‌ها نباید به یکدیگر وابسته باشند. خرابی یک تست نباید باعث خرابی تست‌های دیگر شود.
* **خودکار (Automated):** واحد تست‌ها باید به صورت خودکار قابل اجرا باشند.
* **قابل خواندن (Readable):** کد واحد تست باید واضح و قابل فهم باشد.

**چگونه یک واحد تست طراحی می‌شود؟**

1. **شناسایی واحد مورد نظر:** ابتدا باید مشخص کنید که کدام واحد از کد را می‌خواهید تست کنید. این واحد می‌تواند یک تابع، یک کلاس یا یک متد باشد.
2. **تعریف سناریوهای تست:** برای هر واحد، باید سناریوهای مختلفی را در نظر بگیرید که رفتار آن را در شرایط مختلف بررسی می‌کنند. این سناریوها باید شامل موارد زیر باشند:
* **ورودی‌های معتبر:** تست کردن با ورودی‌هایی که باید به درستی کار کنند.
* **ورودی‌های نامعتبر:** تست کردن با ورودی‌هایی که نباید پذیرفته شوند و باید خطا تولید کنند.
* **شرایط مرزی:** تست کردن با ورودی‌هایی که در لبه‌های محدوده مجاز قرار دارند.
* **موارد خاص:** تست کردن با سناریوهای خاص و غیرمعمول که ممکن است رخ دهند.
3. **نوشتن کد تست:** برای هر سناریو، باید یک تست نوشت که:
* **مقدار ورودی را آماده کند (Arrange):** مقدار ورودی مورد نیاز برای تست را تنظیم می‌کند.
* **تابع یا متد مورد نظر را اجرا کند (Act):** تابع یا متد مورد نظر را با مقدار ورودی آماده شده اجرا می‌کند.
* **خروجی را بررسی کند (Assert):** خروجی تابع یا متد را با خروجی مورد انتظار مقایسه می‌کند و اطمینان حاصل می‌کند که مطابق با انتظارات است.

**ابزارها و فریم‌ورک‌های واحد تست:**

بسته به زبان برنامه‌نویسی مورد استفاده، ابزارها و فریم‌ورک‌های مختلفی برای نوشتن و اجرای واحد تست‌ها وجود دارد. برخی از محبوب‌ترین آنها عبارتند از:

* **Java:** JUnit, TestNG
* **Python:** pytest, unittest
* **JavaScript:** Jest, Mocha, Jasmine
* **C#:** NUnit, xUnit.net
* **C++:** Google Test, Catch2

**مثال (Python با pytest):**

فرض کنید یک تابع ساده به نام `add` داریم که دو عدد را جمع می‌کند:

```python
def add(x, y):
"""Adds two numbers together."""
return x + y
```

حالا می‌خواهیم یک واحد تست برای این تابع با استفاده از pytest بنویسیم:

```python
# filename: test_add.py
from my_module import add # Assuming the add function is in my_module.py
import pytest

def test_add_positive_numbers():
assert add(2, 3) == 5

def test_add_negative_numbers():
assert add(-1, -4) == -5

def test_add_zero():
assert add(0, 5) == 5

def test_add_mixed_numbers():
assert add(-2, 5) == 3

```

**توضیح:**

* `from my_module import add`: این خط تابع `add` را از فایل `my_module.py` وارد می‌کند.
* `pytest`: pytest فریم‌ورکی است که برای نوشتن و اجرای تست‌ها استفاده می‌شود.
* `def test_*()`: هر تابع که با `test_` شروع شود، توسط pytest به عنوان یک تست شناخته می‌شود.
* `assert add(2, 3) == 5`: این یک assert statement است که خروجی تابع `add` را با مقدار مورد انتظار مقایسه می‌کند. اگر خروجی با مقدار مورد انتظار برابر نباشد، یک AssertionError رخ می‌دهد و تست شکست می‌خورد.

**نحوه اجرا:**

برای اجرای این تست‌ها، کافی است در ترمینال به دایرکتوری که فایل `test_add.py` در آن قرار دارد بروید و دستور `pytest` را اجرا کنید. pytest به طور خودکار تمام توابع با نام `test_*` را پیدا و اجرا می‌کند و نتیجه را نمایش می‌دهد.

**نکات مهم:**

* **TDD (Test-Driven Development):** یک رویکرد توسعه نرم‌افزار است که در آن ابتدا تست‌ها نوشته می‌شوند و سپس کد مورد نیاز برای پاس کردن تست‌ها نوشته می‌شود. این روش به طراحی بهتر کد و پوشش تست بالاتر کمک می‌کند.
* **پوشش کد (Code Coverage):** اندازه‌گیری میزان کدی که توسط تست‌ها اجرا می‌شود. هدف این است که پوشش کد را تا حد امکان بالا ببریم تا اطمینان حاصل شود که تمام قسمت‌های کد به خوبی تست شده‌اند.

با رعایت این نکات و استفاده از ابزارها و فریم‌ورک‌های مناسب، می‌توانید واحد تست‌های مؤثری بنویسید که به بهبود کیفیت و قابلیت اطمینان نرم‌افزار شما کمک کنند.