ข้ามไปยังเนื้อหา

บทที่ 16 Testing & CI/CD

ทำไมต้อง Mock?

ปัญหาหลักของการเขียนโปรแกรมกับ ETABS API คือ:

  1. Dependency: ต้องมี ETABS ติดตั้งอยู่บนเครื่องที่รัน Test
  2. Speed: การเปิด/ปิด ETABS กินเวลานานมาก
  3. Cost: เปลือง License ถ้าต้องรัน Test บ่อยๆ
  4. CI/CD: บน GitHub Actions หรือ Cloud Server ไม่มี ETABS ให้ใช้

ทางออกคือการทำ Mocking (จำลองพฤติกรรมของ API)

1. รู้จักกับ unittest.mock

Python มี library มาตรฐานสำหรับการทำ Mocking อยู่แล้ว:

from unittest.mock import MagicMock
# สร้าง Fake ETABS Object
mock_etabs = MagicMock()
mock_model = mock_etabs.SapModel
# กำหนดค่า Return ล่วงหน้า
mock_model.GetModelFilename.return_value = "C:\\Models\\Test.edb"
mock_model.FrameObj.GetNameList.return_value = (0, 2, ["C1", "B1"])
# ลองเรียกใช้งาน
print(mock_model.GetModelFilename())
# Output: C:\Models\Test.edb

2. เขียน Test Case จริงด้วย pytest

สมมติเรามีฟังก์ชันที่ต้องการทดสอบ:

src/main.py
def get_column_count(sap_model):
"""นับจำนวนเสาในโมเดล"""
ret, number, names = sap_model.FrameObj.GetNameList()
count = 0
for name in names:
if name.startswith("C"):
count += 1
return count

เขียน Test Case โดย Inject Mock Object แทนของจริง:

tests/test_main.py
import pytest
from unittest.mock import MagicMock
from src.main import get_column_count
def test_get_column_count():
# 1. Setup Mock
mock_model = MagicMock()
# จำลองว่าในโมเดลมี 3 frame: C1, B1, C2
mock_model.FrameObj.GetNameList.return_value = (0, 3, ["C1", "B1", "C2"])
# 2. Call Function with Mock
result = get_column_count(mock_model)
# 3. Assert
assert result == 2 # ต้องนับได้ 2 (C1, C2)
# 4. Verify Call (เช็คว่า code เราเรียก API จริงไหม)
mock_model.FrameObj.GetNameList.assert_called_once()
# Run: pytest tests/

3. สร้าง Fake ETABS Fixture

เพื่อให้เขียน Test ง่ายขึ้น ควรสร้าง Fixture กลางไว้ใช้ร่วมกัน:

tests/conftest.py
import pytest
from unittest.mock import MagicMock
@pytest.fixture
def mock_sap_model():
model = MagicMock()
# Default behaviors
model.GetModelFilename.return_value = "MockModel.edb"
model.SetPresentUnits.return_value = 0
return model

4. Continuous Integration (CI/CD)

เมื่อเรา Mock ทุกอย่างแล้ว เราสามารถรัน Test บน GitHub Actions ได้เลย! (แม้ Server จะเป็น Linux และไม่มี ETABS)

.github/workflows/python-test.yml

name: Python Tests
on: [push, pull_request]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: "3.11"
- name: Install dependencies
run: |
pip install pytest pandas comtypes
- name: Run tests
run: |
pytest tests/