تست نویسی در Flask با Pytest

فهرست مطالب

“`html

تست نویسی در Flask با Pytest: راهنمای جامع برای توسعه‌دهندگان حرفه‌ای

در دنیای توسعه وب مدرن، تست‌نویسی به یک جزء حیاتی از چرخه‌ی توسعه نرم‌افزار (SDLC) تبدیل شده است. نوشتن تست‌های جامع و مؤثر نه تنها به شناسایی زودهنگام باگ‌ها کمک می‌کند، بلکه به افزایش اطمینان از عملکرد صحیح برنامه، تسهیل فرآیند Refactor و بهبود کلی کیفیت کد منجر می‌شود. Flask، به عنوان یک فریم‌ورک میکرو پایتون، انعطاف‌پذیری بالایی را برای انتخاب ابزارها و رویکردهای مختلف در توسعه و تست‌نویسی ارائه می‌دهد. در این میان، Pytest به عنوان یک فریم‌ورک تست‌نویسی قدرتمند و محبوب در جامعه پایتون، ابزارهای لازم را برای نوشتن تست‌های ساده، خوانا و قابل نگهداری فراهم می‌کند.

این مقاله به عنوان یک راهنمای جامع، به بررسی عمیق تست‌نویسی در Flask با استفاده از Pytest می‌پردازد. هدف ما ارائه رویکردی عملی و گام به گام برای تست‌نویسی مؤثر برنامه‌های Flask است. از پیکربندی اولیه Pytest برای پروژه‌های Flask گرفته تا نوشتن تست‌های واحد (Unit Tests)، تست‌های یکپارچگی (Integration Tests) و تست‌های End-to-End، تمامی جنبه‌های کلیدی تست‌نویسی با مثال‌های کاربردی و توضیحات دقیق پوشش داده خواهند شد.

چرا تست‌نویسی برای برنامه‌های Flask اهمیت دارد؟

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

  • شناسایی زودهنگام باگ‌ها: تست‌نویسی به شما امکان می‌دهد تا باگ‌ها و مشکلات احتمالی را در مراحل اولیه‌ی توسعه شناسایی کنید. این امر از بروز مشکلات جدی در مراحل بعدی جلوگیری کرده و هزینه‌های رفع باگ را به طور چشمگیری کاهش می‌دهد.
  • افزایش اطمینان از عملکرد صحیح: با نوشتن تست‌های جامع، می‌توانید از عملکرد صحیح و پایدار برنامه خود اطمینان حاصل کنید. این امر به ویژه در برنامه‌هایی که با داده‌های حساس سروکار دارند، از اهمیت بالایی برخوردار است.
  • تسهیل فرآیند Refactor: تست‌ها به عنوان یک شبکه‌ی امن عمل می‌کنند که به شما امکان می‌دهد بدون نگرانی از ایجاد باگ‌های جدید، کد خود را Refactor کنید.
  • بهبود کیفیت کد: نوشتن تست‌ها شما را مجبور می‌کند تا در مورد طراحی و معماری کد خود به طور جدی فکر کنید. این امر به نوشتن کد تمیزتر، ماژولارتر و قابل نگهداری‌تر منجر می‌شود.
  • مستندسازی زنده: تست‌ها می‌توانند به عنوان یک نوع مستندسازی زنده عمل کنند که نحوه استفاده از کد و رفتار مورد انتظار آن را نشان می‌دهند.
  • افزایش اعتماد به نفس: با داشتن یک مجموعه‌ی تست قوی، می‌توانید با اطمینان بیشتری تغییرات را در کد خود اعمال کنید و از استقرار بدون مشکل آن اطمینان حاصل کنید.

پیکربندی Pytest برای پروژه‌های Flask

برای شروع تست‌نویسی در Flask با Pytest، ابتدا باید Pytest و پلاگین‌های مورد نیاز را نصب و پیکربندی کنید. مراحل زیر را دنبال کنید:

نصب Pytest و پلاگین‌های ضروری

با استفاده از pip، Pytest و پلاگین‌های pytest-flask و pytest-cov را نصب کنید:

pip install pytest pytest-flask pytest-cov
 
  • pytest-flask: این پلاگین ابزارهای خاصی را برای تست برنامه‌های Flask فراهم می‌کند، از جمله دسترسی آسان به اپلیکیشن Flask، Client و Context.
  • pytest-cov: این پلاگین گزارش پوشش کد را ارائه می‌دهد، که به شما کمک می‌کند تا اطمینان حاصل کنید که تست‌های شما بخش‌های مهم کد را پوشش می‌دهند.

ایجاد فایل پیکربندی Pytest (pytest.ini)

برای پیکربندی Pytest، یک فایل به نام pytest.ini در ریشه پروژه خود ایجاد کنید. این فایل به شما امکان می‌دهد تنظیمات پیش‌فرض Pytest را تغییر دهید و گزینه‌هایی مانند مسیر تست‌ها، افزونه‌های فعال و تنظیمات مربوط به پوشش کد را مشخص کنید.

نمونه‌ای از فایل pytest.ini:

[pytest]
 testpaths = tests
 flask_app = your_project.app
 flask_config = testing
 addopts = --cov=your_project --cov-report term-missing
 
  • testpaths: مسیری که Pytest به دنبال فایل‌های تست در آن می‌گردد. در اینجا، مسیر tests مشخص شده است.
  • flask_app: نام ماژول و متغیر اپلیکیشن Flask شما. به عنوان مثال، اگر اپلیکیشن Flask شما در فایل your_project/app.py تعریف شده باشد، مقدار این گزینه باید your_project.app باشد.
  • flask_config: نام پیکربندی Flask مورد استفاده برای تست‌ها. معمولاً، یک پیکربندی جداگانه برای تست‌ها ایجاد می‌شود که تنظیماتی مانند پایگاه داده‌ی موقت و غیره را شامل می‌شود.
  • addopts: گزینه‌های اضافی برای Pytest. در اینجا، گزینه‌های مربوط به پوشش کد مشخص شده‌اند.
    • --cov=your_project: Pytest را برای جمع‌آوری اطلاعات پوشش کد برای بسته your_project فعال می‌کند.
    • --cov-report term-missing: گزارشی از خطوط کد از دست رفته در ترمینال نمایش می‌دهد.

نوشتن تست‌های واحد (Unit Tests) برای برنامه‌های Flask

تست‌های واحد بر روی تست کردن اجزای منفرد کد، مانند توابع، کلاس‌ها و ماژول‌ها تمرکز دارند. هدف از تست واحد، اطمینان حاصل کردن از این است که هر جزء به درستی و مطابق با انتظار عمل می‌کند.

ساختاردهی تست‌های واحد

بهترین روش برای ساختاردهی تست‌های واحد، ایجاد یک دایرکتوری جداگانه به نام tests در ریشه پروژه است. در این دایرکتوری، فایل‌های تستی را ایجاد کنید که نام آنها با پیشوند test_ شروع می‌شود.

به عنوان مثال:

your_project/
 ├── your_project/
 │   ├── __init__.py
 │   ├── app.py
 │   ├── models.py
 │   └── ...
 ├── tests/
 │   ├── __init__.py
 │   ├── test_models.py
 │   └── ...
 ├── pytest.ini
 └── ...
 

نوشتن تست‌های واحد برای مدل‌های Flask

فرض کنید یک مدل SQLAlchemy به نام User در فایل your_project/models.py تعریف کرده‌اید:

from your_project.app import db

 class User(db.Model):
  id = db.Column(db.Integer, primary_key=True)
  username = db.Column(db.String(80), unique=True, nullable=False)
  email = db.Column(db.String(120), unique=True, nullable=False)

  def __repr__(self):
   return f'<User {self.username}>'
 

برای تست مدل User، یک فایل به نام tests/test_models.py ایجاد کنید:

import pytest
 from your_project.models import User

 def test_create_user(app):
  with app.app_context():
   user = User(username='testuser', email='testuser@example.com')
   db = app.db
   db.session.add(user)
   db.session.commit()

   retrieved_user = User.query.filter_by(username='testuser').first()
   assert retrieved_user == user
   assert retrieved_user.email == 'testuser@example.com'
 

در این مثال:

  • app: یک fixture از pytest-flask است که یک اپلیکیشن Flask تست را در اختیار شما قرار می‌دهد.
  • app.app_context(): یک Context اپلیکیشن Flask را ایجاد می‌کند که برای دسترسی به منابعی مانند پایگاه داده مورد نیاز است.
  • db = app.db: به شیء پایگاه داده SQLAlchemy دسترسی پیدا می‌کند.
  • db.session.add(user) و db.session.commit(): یک کاربر جدید را به پایگاه داده اضافه و تغییرات را ذخیره می‌کنند.
  • User.query.filter_by(username='testuser').first(): کاربری را با نام کاربری مشخص از پایگاه داده بازیابی می‌کند.
  • assert retrieved_user == user و assert retrieved_user.email == 'testuser@example.com': ادعا می‌کنند که کاربر بازیابی شده با کاربر ایجاد شده مطابقت دارد و ایمیل آن صحیح است.

نوشتن تست‌های یکپارچگی (Integration Tests) برای برنامه‌های Flask

تست‌های یکپارچگی بر روی تست تعامل بین اجزای مختلف کد تمرکز دارند. هدف از تست یکپارچگی، اطمینان حاصل کردن از این است که اجزای مختلف برنامه به درستی با یکدیگر کار می‌کنند.

نوشتن تست‌های یکپارچگی برای مسیرهای Flask

فرض کنید یک مسیر Flask به نام /users در فایل your_project/app.py تعریف کرده‌اید:

from flask import Flask, jsonify

 app = Flask(__name__)

 @app.route('/users')
 def list_users():
  users = [{'id': 1, 'username': 'testuser'}]
  return jsonify(users)
 

برای تست مسیر /users، یک فایل به نام tests/test_routes.py ایجاد کنید:

import pytest
 import json

 def test_list_users(client):
  response = client.get('/users')
  data = json.loads(response.data)

  assert response.status_code == 200
  assert len(data) == 1
  assert data[0]['username'] == 'testuser'
 

در این مثال:

  • client: یک fixture از pytest-flask است که یک Client تست را در اختیار شما قرار می‌دهد.
  • client.get('/users'): یک درخواست GET به مسیر /users ارسال می‌کند.
  • json.loads(response.data): پاسخ JSON را تجزیه می‌کند.
  • assert response.status_code == 200: ادعا می‌کند که کد وضعیت پاسخ 200 است (OK).
  • assert len(data) == 1: ادعا می‌کند که پاسخ حاوی یک کاربر است.
  • assert data[0]['username'] == 'testuser': ادعا می‌کند که نام کاربری کاربر testuser است.

نوشتن تست‌های End-to-End (E2E) برای برنامه‌های Flask

تست‌های End-to-End (E2E) بر روی تست کل برنامه از دیدگاه کاربر نهایی تمرکز دارند. هدف از تست E2E، اطمینان حاصل کردن از این است که برنامه به طور کامل و صحیح کار می‌کند.

استفاده از Selenium یا Playwright برای تست‌های E2E

برای نوشتن تست‌های E2E برای برنامه‌های Flask، معمولاً از ابزارهایی مانند Selenium یا Playwright استفاده می‌شود. این ابزارها به شما امکان می‌دهند تا مرورگر را به طور خودکار کنترل کرده و تعاملات کاربر را شبیه‌سازی کنید.

مثال با Selenium (نیاز به نصب Selenium و WebDriver):

import pytest
 from selenium import webdriver

 @pytest.fixture(scope="session")
 def browser():
  driver = webdriver.Chrome() # یا Firefox، Edge، ...
  yield driver
  driver.quit()

 def test_user_login(browser, live_server):
  browser.get(live_server.url + '/login')
  username_input = browser.find_element("id", "username")
  password_input = browser.find_element("id", "password")
  login_button = browser.find_element("id", "login_button")

  username_input.send_keys("testuser")
  password_input.send_keys("password")
  login_button.click()

  assert browser.current_url == live_server.url + '/dashboard'
 

در این مثال:

  • browser: یک fixture است که یک شیء WebDriver را برای کنترل مرورگر فراهم می‌کند.
  • live_server: یک fixture از pytest-flask است که یک سرور Flask زنده را برای تست فراهم می‌کند.
  • browser.get(live_server.url + '/login'): مرورگر را به صفحه ورود به سیستم هدایت می‌کند.
  • browser.find_element("id", "username"): یک عنصر HTML را با ID مشخص شده پیدا می‌کند.
  • username_input.send_keys("testuser"): متن را در فیلد ورودی نام کاربری وارد می‌کند.
  • login_button.click(): روی دکمه ورود به سیستم کلیک می‌کند.
  • assert browser.current_url == live_server.url + '/dashboard': ادعا می‌کند که URL فعلی مرورگر صفحه داشبورد است.

استفاده از Fixtureها در Pytest برای برنامه‌های Flask

Fixtureها در Pytest توابع تستی هستند که قبل از اجرای تست‌ها اجرا می‌شوند و منابع مورد نیاز را برای تست‌ها فراهم می‌کنند. استفاده از fixtureها به شما کمک می‌کند تا کد تست خود را سازماندهی کنید، از تکرار کد جلوگیری کنید و تست‌های خود را قابل خواندن‌تر و نگهداری‌تر کنید.

Fixtureهای پیش‌فرض pytest-flask

پلاگین pytest-flask چندین fixture پیش‌فرض را برای تست برنامه‌های Flask فراهم می‌کند، از جمله:

  • app: یک اپلیکیشن Flask تست را فراهم می‌کند.
  • client: یک Client تست را فراهم می‌کند که به شما امکان می‌دهد درخواست‌های HTTP را به اپلیکیشن Flask ارسال کنید.
  • request_context: یک Context درخواست Flask را فراهم می‌کند.
  • live_server: یک سرور Flask زنده را برای تست‌های E2E فراهم می‌کند.

ایجاد Fixtureهای سفارشی

علاوه بر fixtureهای پیش‌فرض، می‌توانید fixtureهای سفارشی خود را نیز ایجاد کنید. برای ایجاد یک fixture سفارشی، از دکوراتور @pytest.fixture استفاده کنید.

مثال:

import pytest
 from your_project.models import User

 @pytest.fixture
 def test_user(app):
  with app.app_context():
   user = User(username='testuser', email='testuser@example.com')
   db = app.db
   db.session.add(user)
   db.session.commit()
   yield user
   db.session.delete(user)
   db.session.commit()
 

در این مثال:

  • @pytest.fixture: تابع test_user را به عنوان یک fixture تعریف می‌کند.
  • yield user: مقدار user را به تست‌هایی که از این fixture استفاده می‌کنند، برمی‌گرداند.
  • db.session.delete(user) و db.session.commit(): پس از اجرای تست‌ها، کاربر ایجاد شده را از پایگاه داده حذف می‌کنند.

برای استفاده از fixture سفارشی خود، آن را به عنوان یک آرگومان به تابع تست خود اضافه کنید:

def test_user_username(test_user):
  assert test_user.username == 'testuser'
 

بهترین روش‌ها برای تست‌نویسی مؤثر در Flask با Pytest

برای نوشتن تست‌های مؤثر و قابل نگهداری برای برنامه‌های Flask با استفاده از Pytest، به نکات زیر توجه کنید:

  • نوشتن تست‌ها قبل از نوشتن کد (TDD): رویکرد توسعه تست‌محور (TDD) به شما کمک می‌کند تا قبل از نوشتن کد، تست‌ها را بنویسید. این امر به شما کمک می‌کند تا نیازهای خود را به طور دقیق تعریف کنید و کدی بنویسید که به طور خاص برای پاس کردن تست‌ها طراحی شده است.
  • نوشتن تست‌های واحد، یکپارچگی و E2E: برای پوشش کامل برنامه خود، تست‌های واحد، یکپارچگی و E2E را بنویسید.
  • استفاده از Fixtureها: از fixtureها برای سازماندهی کد تست خود، جلوگیری از تکرار کد و افزایش خوانایی و نگهداری‌پذیری تست‌ها استفاده کنید.
  • استفاده از Mocks و Stubs: برای تست اجزای مستقل، از mocks و stubs برای شبیه‌سازی وابستگی‌های خارجی استفاده کنید.
  • اجرای تست‌ها به طور منظم: تست‌های خود را به طور منظم اجرا کنید، به خصوص پس از هر تغییر در کد.
  • استفاده از CI/CD: از یک سیستم ادغام مداوم/تحویل مداوم (CI/CD) برای اجرای خودکار تست‌ها و استقرار برنامه خود استفاده کنید.
  • گزارش پوشش کد: از گزارش پوشش کد برای اطمینان حاصل کردن از این که تست‌های شما بخش‌های مهم کد را پوشش می‌دهند، استفاده کنید.

نتیجه‌گیری

تست‌نویسی یک جنبه ضروری از توسعه برنامه‌های Flask است. با استفاده از Pytest و رویکردهای ذکر شده در این مقاله، می‌توانید تست‌های جامع، خوانا و قابل نگهداری برای برنامه‌های Flask خود بنویسید و از عملکرد صحیح، پایدار و با کیفیت بالای برنامه خود اطمینان حاصل کنید. به یاد داشته باشید که تست‌نویسی یک فرآیند مستمر است و با پیشرفت پروژه شما باید تست‌های خود را نیز به‌روز نگه دارید.

“`

“تسلط به برنامه‌نویسی پایتون با هوش مصنوعی: آموزش کدنویسی هوشمند با ChatGPT”

قیمت اصلی 2.290.000 ریال بود.قیمت فعلی 1.590.000 ریال است.

"تسلط به برنامه‌نویسی پایتون با هوش مصنوعی: آموزش کدنویسی هوشمند با ChatGPT"

"با شرکت در این دوره جامع و کاربردی، به راحتی مهارت‌های برنامه‌نویسی پایتون را از سطح مبتدی تا پیشرفته با کمک هوش مصنوعی ChatGPT بیاموزید. این دوره، با بیش از 6 ساعت محتوای آموزشی، شما را قادر می‌سازد تا به سرعت الگوریتم‌های پیچیده را درک کرده و اپلیکیشن‌های هوشمند ایجاد کنید. مناسب برای تمامی سطوح با زیرنویس فارسی حرفه‌ای و امکان دانلود و تماشای آنلاین."

ویژگی‌های کلیدی:

بدون نیاز به تجربه قبلی برنامه‌نویسی

زیرنویس فارسی با ترجمه حرفه‌ای

۳۰ ٪ تخفیف ویژه برای دانشجویان و دانش آموزان