01204223/flask-testing

จาก Theory Wiki
ไปยังการนำทาง ไปยังการค้นหา
หน้านี้เป็นส่วนหนึ่งของวิชา 01204223

เราจะทดสอบส่วน Flask backend ด้วย pytest โดยการทดสอบเราจะเป็นกึ่ง ๆ unit test ที่จะเน้นทดสอบแค่บาง api end-point แต่เนื่องจาก backend เรามีการติดต่อกับ database ผ่านทาง SQLAlchemy ซึ่ง mock ยุ่งยากมาก เราจึงจะไม่ได้ mock แต่จะสร้าง test database มาแทน ทำให้การทำงานของ test เรานั้นจะมีการติดต่อไปยังฐานข้อมูลด้วย (จึงอาจจะเป็น unit test ที่ติดต่อกับระบบอื่นๆ มากเกินไปสักนิด)

ติดตั้งและตั้งค่าเริ่มต้น

เข้าไปทำงานในไดเร็กทอรี backend

ก่อนอื่นเราจะต้อง activate virtual environment ก่อน

จากนั้นจะติดตั้ง pytest โดยเรียก

pip install pytest

ถ้าติดตั้งเรียบร้อยจะเรียก

pytest

ได้ และเห็นผลลัพธ์ที่แสดงว่าเราไม่มี test case อะไรเลย (จะมีข้อความว่า collected 0 items)

ก่อนจะทำงานต่อ ให้เก็บรายการของ packages ลงใน requirements.txt โดยสั่ง

pip freeze > requirements.txt

เพื่อที่เราจะได้ไปเทสใน github action ได้ต่อไป

ตัวอย่างเทสเคสแรก

เราจะสร้างไดเร็กทอรี backend/tests เพื่อเก็บไฟล์ test case ต่างๆ จากนั้นให้สร้างไฟล์ backend/tests/test_models.py ที่มีเทสเคสตัวอย่างดังนี้

def test_add():
    assert 2+3 == 5

สังเกตว่าฟังก์ชันชื่อขึ้นต้นด้วย test และอยู่ในไฟล์ที่ชื่อขึ้นต้นด้วย test ซึ่งเป็นกฎที่ pytest ใช้ในการหา test functions

เมื่อเขียนเสร็จแล้ว ให้ลองเรียก (เรียกจากไดเร็กทอรี backend)

pytest

จะเห็นผลลัพธ์ดังนี้

============================= test session starts ==============================
platform linux -- Python 3.13.7, pytest-8.3.4, pluggy-1.6.0
rootdir: /home/jittat/prog/test/flask-react-todo-start/backend
collected 1 item                                                               

tests/test_models.py .                                                   [100%]

============================== 1 passed in 0.01s ===============================

แสดงว่าเทสทำงานถูกต้อง ให้ลองแก้ฟังก์ชันด้านบนเป็น

def test_add():
    assert 2+3 == 6

แล้วลองเรียก pytest อีกครั้ง จะเห็นว่ามีการฟ้องว่าทดสอบไม่ผ่าน

ให้ลบฟังก์ชัน test_add ออกก่อน เพราะเราจะทดลองเพิ่มฟังก์ชันเทสแบบจริงจัง

ทดสอบการตรวจสอบรหัสผ่าน

เราจะทดสอบฟังก์ชัน set_password และ check_password ที่เราเขียนไว้ในคลาส User โดยเราจะสร้าง test functions เพื่อทดสอบสองฟังก์ชันดังนี้

def test_check_correct_password():
    user = User()
    user.set_password("testpassword")
    assert user.check_password("testpassword") == True

def test_check_incorrect_password():
    user = User()
    user.set_password("testpassword")
    assert user.check_password("testpassworx") == False

แต่ฟังก์ชันทั้งสองยังไม่สามารถทำงานได้ เพราะว่าเราต้อง import คลาส User ให้ได้ก่อน แต่ test cases เราอยู่ในไดเร็กทอรี tests ซึ่งทำให้การสั่ง import ตรง ๆ จะทำไม่ได้

เพื่อความสะดวกในการจัดการ test และยังจำเป็นในการสร้าง test database เราจะเพิ่มโค้ดเพื่อตั้งค่าและเตรียมสภาพแวดล้อมเพื่อการทดสอบเสียก่อน

ให้สร้างไฟล์ชื่อ tests/conftest.py ซึ่งเป็นไฟล์สำหรับตั้งค่าของ pytest โดยใส่คำสั่งดังนี้

import sys
from pathlib import Path

PROJECT_ROOT = Path(__file__).resolve().parents[1]
if str(PROJECT_ROOT) not in sys.path:
    sys.path.insert(0, str(PROJECT_ROOT))

คำสั่งดังกล่าวจะเพิ่ม path ของ backend ลงไปใน sys.path ทำให้สามารถ import คลาส User ได้

จากนั้นให้แก้ไฟล์ tests/test_models.py ให้เป็น

from models import User

def test_check_correct_password():
    user = User()
    user.set_password("testpassword")
    assert user.check_password("testpassword") == True

def test_check_incorrect_password():
    user = User()
    user.set_password("testpassword")
    assert user.check_password("testpassworx") == False

แล้วทดลองเรียก pytest เพื่อทำงาน และดูผลลัพธ์การทดสอบ