การทดสอบด้วย pytest
jest → pytest
หัวข้อที่มีชื่อว่า “jest → pytest”ถ้าคุ้นกับ jest อยู่แล้ว โครงสร้างของ pytest จะคุ้นตาทันที แต่ syntax เรียบง่ายกว่าอย่างน่าพอใจ ไม่มี .toBe() ไม่มี wrapper expect() เพราะ pytest ใช้ assert ของ Python ตรง ๆ แล้ว rewrite ให้เบื้องหลัง เพื่อโชว์ diff ที่อ่านรู้เรื่องตอน test fail
การติดตั้ง pytest
หัวข้อที่มีชื่อว่า “การติดตั้ง pytest”รันในเทอร์มินัลของคุณ:
pip install pytest# หรือ:uv add --dev pytest
# รัน tests ทั้งหมดpytest
# รันพร้อม verbose outputpytest -v
# รัน file เฉพาะpytest tests/test_math.py
# รัน test เฉพาะโดยชื่อpytest tests/test_math.py::test_addเขียน test แรกของคุณ
หัวข้อที่มีชื่อว่า “เขียน test แรกของคุณ”// jest — TypeScriptimport { add, greet } from './math';
describe('math utils', () => { test('adds two numbers', () => { expect(add(2, 3)).toBe(5); });
test('greet returns a string', () => { expect(greet('Alice')).toBe('Hello, Alice!'); });
test('throws on negative input', () => { expect(() => add(-1, 0)).toThrow('negative'); });});# pytest — Python# ไฟล์ต้องขึ้นต้นด้วย test_ หรือลงท้ายด้วย _test.py# Functions ต้องขึ้นต้นด้วย test_
from math_utils import add, greetimport pytest
def test_adds_two_numbers(): assert add(2, 3) == 5
def test_greet_returns_string(): assert greet("Alice") == "Hello, Alice!"
def test_raises_on_negative_input(): with pytest.raises(ValueError, match="negative"): add(-1, 0)กฎ Test Discovery
หัวข้อที่มีชื่อว่า “กฎ Test Discovery”pytest ค้นหา tests อัตโนมัติ — ไม่ต้อง config test runner เพื่อเริ่มต้น:
| กฎ | pytest | jest |
|---|---|---|
| Pattern ของไฟล์ | test_*.py หรือ *_test.py | *.test.ts หรือ *.spec.ts |
| Pattern ของ function | test_* | test(...) หรือ it(...) |
| Pattern ของ class | Test* (ไม่มี __init__) | describe(...) |
| Setup | setup_method / fixtures | beforeEach |
| Teardown | teardown_method / fixtures | afterEach |
Fixtures — beforeEach ของ pytest
หัวข้อที่มีชื่อว่า “Fixtures — beforeEach ของ pytest”ฝั่ง jest คุณใช้ beforeEach / afterEach ส่วน pytest ใช้ fixture ที่เป็น function ที่ inject เข้ามาเป็น dependency คอย setup resource และจะ teardown ต่อท้ายด้วยก็ได้ fixture ทำได้มากกว่า beforeEach เพราะ compose ต่อกันได้และกำหนด scope เองได้
// jest beforeEachlet db: MockDatabase;
beforeEach(() => { db = new MockDatabase(); db.seed([{ id: 1, name: 'Alice' }]);});
afterEach(() => { db.close();});
test('finds a user', () => { expect(db.find(1)).toEqual({ id: 1, name: 'Alice' });});# pytest fixture — เทียบกับ beforeEach/afterEachimport pytest
@pytest.fixturedef db(): database = MockDatabase() database.seed([{"id": 1, "name": "Alice"}]) yield database # test รันที่นี่ database.close() # teardown หลัง yield
def test_finds_a_user(db): # pytest inject fixture assert db.find(1) == {"id": 1, "name": "Alice"}Parametrize — tests แบบ data-driven
หัวข้อที่มีชื่อว่า “Parametrize — tests แบบ data-driven”// jest — test.each สำหรับ data-driven teststest.each([ [1, 2, 3], [0, 0, 0], [-1, 1, 0],])('add(%i, %i) = %i', (a, b, expected) => { expect(add(a, b)).toBe(expected);});# pytest — @pytest.mark.parametrizeimport pytest
@pytest.mark.parametrize("a, b, expected", [ (1, 2, 3), (0, 0, 0), (-1, 1, 0),])def test_add(a, b, expected): assert add(a, b) == expectedลองด้วยตัวเอง — assertions ในการทำงานจริง
หัวข้อที่มีชื่อว่า “ลองด้วยตัวเอง — assertions ในการทำงานจริง”# pytest-style assertions ทำงานใน plain Python ด้วยdef add(a: int, b: int) -> int: return a + b
def test_basic(): assert add(2, 3) == 5 assert add(0, 0) == 0
def test_string(): message = "Hello, World!" assert "World" in message assert message.startswith("Hello") assert len(message) == 13
# รัน tests ด้วยตนเองtest_basic()test_string()print("All assertions passed!")Loading Python runtime (first run only)…
Playground note: snippet ข้างต้นแสดง Python
assertstatements แบบธรรมดา pytest runner จริง (test discovery, fixtures, parametrize,--cov) ต้องการ terminal ที่ติดตั้งpytestรันpytest -vใน project ของคุณเพื่อดูประสบการณ์จริง