รูปแบบโครงสร้าง Automation Project
จบบทนี้แล้วคุณจะ...
- อธิบายได้ว่าโครงสร้าง project ที่ดีมีลักษณะอย่างไร
- รู้จัก folder organization มาตรฐาน (tests/, pages/, fixtures/, utils/)
- เข้าใจ Page Object Model (POM) ในระดับ concept
- เข้าใจหลัก separation of concerns ใน automation
- จัดโครงสร้าง project ให้เป็นระเบียบได้
1 · ทำไมโครงสร้าง project ถึงสำคัญ
ลองนึกภาพ automation project ที่มี test 300 ไฟล์:
แบบไม่มีโครงสร้าง:
project/
├── test1.js
├── test2.js
├── test_login.js
├── helper.js
├── test_cart_new.js
├── test_cart_old.js
├── utils.js
├── more_utils.js
├── login_page.js
├── test3_FINAL.js
├── test3_FINAL_v2.js
├── ...อีก 290 ไฟล์...
คุณจะหาว่า test ไหนทดสอบอะไร? code ที่ใช้ร่วมกันอยู่ตรงไหน? ไฟล์ไหนที่ยังใช้อยู่?
แบบมีโครงสร้าง:
project/
├── tests/
│ ├── auth/
│ │ ├── login.test.js
│ │ └── registration.test.js
│ ├── cart/
│ │ ├── add-to-cart.test.js
│ │ └── checkout.test.js
│ └── search/
│ └── product-search.test.js
├── pages/
│ ├── login.page.js
│ ├── cart.page.js
│ └── search.page.js
├── fixtures/
│ ├── users.json
│ └── products.json
├── utils/
│ ├── api-helper.js
│ └── date-helper.js
└── config/
├── dev.config.js
└── staging.config.js
แค่ดูโครงสร้าง ก็รู้ทันทีว่าอะไรอยู่ตรงไหน
2 · Folder Organization มาตรฐาน
tests/
- เก็บ test files ทั้งหมด จัดกลุ่มตาม feature/module
- ตั้งชื่อไฟล์ให้บอกว่าทดสอบอะไร เช่น
login.test.js - จัดกลุ่มตาม feature:
tests/auth/,tests/cart/,tests/payment/
pages/ (หรือ page-objects/)
- เก็บ Page Object files ที่ wrap การทำงานของแต่ละหน้า
- แต่ละไฟล์แทนหนึ่งหน้า/component เช่น
login.page.js - เก็บ locators และ actions ของหน้านั้น
fixtures/
- เก็บ test data ที่เป็น static
- JSON, CSV, หรือ format อื่น ๆ
- เช่น: test users, product catalogs, expected results
utils/ (หรือ helpers/)
- เก็บ utility functions ที่ใช้ร่วมกันหลาย test
- เช่น: date formatting, API helpers, data generators
config/
- เก็บ configuration files สำหรับแต่ละ environment
- Base URL, credentials path, timeout settings
3 · Page Object Model (POM) — Concept Level
ปัญหาที่ POM แก้
สมมติคุณมี 20 test ที่ต้อง login ทุก test มี code แบบนี้:
// ใน test ที่ 1
หา element "#username" แล้วพิมพ์ "admin"
หา element "#password" แล้วพิมพ์ "pass123"
หา element "#login-btn" แล้วคลิก
// ใน test ที่ 2 (copy มาเหมือนกัน)
หา element "#username" แล้วพิมพ์ "admin"
หา element "#password" แล้วพิมพ์ "pass123"
หา element "#login-btn" แล้วคลิก
// ...อีก 18 test...
ถ้าวันหนึ่ง dev เปลี่ยน #username เป็น #email → ต้องแก้ 20 ที่!
POM คืออะไร
Page Object Model คือแนวคิดที่ แยก locators และ actions ของแต่ละหน้า ออกจาก test logic
// LoginPage (page object)
- locator: username = "#username"
- locator: password = "#password"
- locator: loginBtn = "#login-btn"
- action: login(user, pass) = พิมพ์ username, พิมพ์ password, คลิก loginBtn
// Test (ใช้ page object)
loginPage.login("admin", "pass123")
ถ้า dev เปลี่ยน #username เป็น #email → แก้แค่ที่เดียวใน LoginPage
ประโยชน์ของ POM
- DRY (Don't Repeat Yourself) — locators อยู่ที่เดียว ไม่ duplicate
- Easy maintenance — UI เปลี่ยน แก้แค่ page object ไม่ต้องแก้ test
- Readable tests — test อ่านเข้าใจง่ายเพราะเรียก action ที่มีความหมาย
- Reusable — หลาย test ใช้ page object เดียวกันได้
4 · Separation of Concerns
แต่ละส่วนของ automation project ควรรับผิดชอบเรื่องเดียว:
| Layer | รับผิดชอบ | ตัวอย่าง |
|---|---|---|
| Test | ลำดับขั้นตอนและ assertions | "login → เพิ่มสินค้า → เช็คตะกร้า" |
| Page Object | Locators และ actions ของแต่ละหน้า | "หา element, คลิก, พิมพ์" |
| Fixtures | Test data | "user: admin, pass: 123" |
| Utils | Helper functions ที่ไม่ผูกกับหน้าใดหน้าหนึ่ง | "format date, generate random email" |
| Config | Environment settings | "base URL, timeout, browser" |
ทำไมต้องแยก?
- เปลี่ยน UI → แก้แค่ page objects
- เปลี่ยน test data → แก้แค่ fixtures
- เปลี่ยน environment → แก้แค่ config
- เพิ่ม test case → เขียนแค่ test file ใหม่ โดยใช้ page objects + fixtures ที่มีอยู่
5 · Config Management
สิ่งที่ควรอยู่ใน config
- Base URL ของ application
- Browser ที่จะใช้ test (Chrome, Firefox, etc.)
- Timeout settings (default wait, page load timeout)
- Screenshot/video path สำหรับ failure
- Parallel execution settings
- Reporter settings (HTML report, JUnit XML)
สิ่งที่ไม่ควรอยู่ใน config (หรือ code)
- Passwords / API keys → ใช้ environment variables
- Personal data → ใช้ fixtures ที่ generate
- Hardcoded waits → ใช้ config timeout
แบบฝึก: จัดโครงสร้าง Project
โจทย์
คุณได้รับ automation project ที่มีไฟล์ดังนี้ (ไม่มีโครงสร้าง):
my-project/
├── test_login_success.js
├── test_login_fail.js
├── test_add_to_cart.js
├── test_remove_from_cart.js
├── test_checkout_credit.js
├── test_checkout_cod.js
├── test_search_product.js
├── test_filter_by_price.js
├── login_helpers.js
├── cart_helpers.js
├── search_helpers.js
├── checkout_helpers.js
├── test_users.json
├── test_products.json
├── test_credit_cards.json
├── date_utils.js
├── api_utils.js
├── email_utils.js
├── config_dev.js
├── config_staging.js
├── config_prod.js
จัดโครงสร้างใหม่ให้เป็นระเบียบ
ดูคำตอบแนะนำ
my-project/
├── tests/
│ ├── auth/
│ │ ├── login-success.test.js
│ │ └── login-fail.test.js
│ ├── cart/
│ │ ├── add-to-cart.test.js
│ │ └── remove-from-cart.test.js
│ ├── checkout/
│ │ ├── checkout-credit.test.js
│ │ └── checkout-cod.test.js
│ └── search/
│ ├── search-product.test.js
│ └── filter-by-price.test.js
├── pages/
│ ├── login.page.js ← จาก login_helpers.js
│ ├── cart.page.js ← จาก cart_helpers.js
│ ├── search.page.js ← จาก search_helpers.js
│ └── checkout.page.js ← จาก checkout_helpers.js
├── fixtures/
│ ├── users.json ← จาก test_users.json
│ ├── products.json ← จาก test_products.json
│ └── credit-cards.json ← จาก test_credit_cards.json
├── utils/
│ ├── date-helper.js ← จาก date_utils.js
│ ├── api-helper.js ← จาก api_utils.js
│ └── email-helper.js ← จาก email_utils.js
└── config/
├── dev.config.js
├── staging.config.js
└── prod.config.js
หลักการที่ใช้:
- tests/ จัดกลุ่มตาม feature (auth, cart, checkout, search)
- pages/ เปลี่ยนจาก "helpers" เป็น page objects — แต่ละไฟล์แทนหนึ่งหน้า
- fixtures/ รวม test data ไว้ที่เดียว ตั้งชื่อให้ชัดเจน
- utils/ เก็บ helpers ที่ไม่ผูกกับหน้าใดหน้าหนึ่ง
- config/ แยก config ตาม environment
- Naming: ใช้ kebab-case, เติม
.test.js/.page.jsเพื่อบอกประเภท
สิ่งที่ต้องเอาติดตัวไปจากบทนี้
- โครงสร้างที่ดี ทำให้หาไฟล์ง่าย, maintain ง่าย, onboard คนใหม่ง่าย
- Page Object Model แยก locators/actions ออกจาก test logic — UI เปลี่ยน แก้ที่เดียว
- Separation of concerns — test, page object, fixture, utils, config แต่ละส่วนรับผิดชอบเรื่องเดียว
- จัดกลุ่มตาม feature ไม่ใช่ตามประเภทไฟล์ — ง่ายต่อการหาและ maintain
- โครงสร้างที่ดีตั้งแต่ต้น ประหยัดเวลามหาศาล เมื่อ project โตขึ้น