ทำ UI Test ด้วย Selenium: ลดปวดหัวงานเช็คเว็บแบบแมนนวล
โอ้ยยย... เหนื่อยจริงไหมกับการมานั่งคลิกๆ ตรวจสอบหน้าเว็บเองทุกรอบที่แก้โค้ด? คือมันก็ดีแหละถ้าเว็บเล็กๆ แต่พอโปรเจกต์ใหญ่ขึ้นมาหน่อย หรือแก้เยอะๆ นี่... บอกเลยว่าไม่ไหว! เราก็เลยต้องพึ่งตัวช่วยอย่าง Selenium ไงล่ะ มันช่วยให้เราเขียนโค้ดสั่งให้บราวเซอร์ทำงานเองเลยนะ เจ๋งป้ะล่ะ!
เตรียมตัวก่อนลุย
ก่อนอื่นเลยต้องมี Python ก่อนนะ อันนี้เบสิคมาก ใครไม่มีไปโหลดมาซะ! แล้วก็ pip install selenium ไปเลย
pip install selenium
ทีนี้ปัญหามันอยู่ตรง WebDriver นี่แหละ! คือ Selenium มันต้องมี 'คนขับ' ให้มันไง เป็นตัวเชื่อมกับบราวเซอร์ของเรา Chrome, Firefox, Edge อะไรก็ได้หมดแหละ แต่ต้องไปโหลดมานะเว้ยยย... โหลดตามเวอร์ชั่นบราวเซอร์ที่เราใช้เป๊ะๆ ด้วย ไม่งั้นมี Error จ้าาาาาาาาาา SessionNotCreatedException มาแน่ๆ
ตัวอย่าง Error ที่เคยเจอประจำ:
selenium.common.exceptions.SessionNotCreatedException: Message: session not created: This version of ChromeDriver only supports Chrome version XX
Current browser version is YY with binary path C:\Program Files\Google\Chrome\Application\chrome.exe
ไอ้เนี่ยแหละคืออาการ WebDriver ไม่ตรงเวอร์ชั่นโคตรคลาสสิค! วิธีแก้ก็ง่ายๆ เลย แค่ไปโหลด ChromeDriver (ถ้าใช้ Chrome) ที่ตรงกับ Chrome เวอร์ชั่นปัจจุบันของเราเป๊ะๆ แล้วก็เอาไฟล์ chromedriver.exe ไปวางไว้ใน Path ที่เข้าถึงได้ (เช่น โฟลเดอร์ที่รันโค้ด หรือใน System PATH เลยก็ได้)
เริ่มเขียนโค้ด Test แรก
มาลองเขียนโค้ดง่ายๆ ให้มันไปเปิด Google แล้วลองค้นหาคำว่า "Selenium" กันดู:
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
import time # ไว้ดูผลเฉยๆ ไม่ควรใช้ในงานจริงจังนะ
# ระบุ path ไปยัง chromedriver ของเรา
# ถ้าอยู่ใน PATH ของระบบอยู่แล้ว ไม่ต้องระบุก็ได้
driver_path = 'C:/path/to/your/chromedriver.exe' # แก้ด้วย path ของคุณ
# เริ่มต้น WebDriver (ในที่นี้ใช้ Chrome)
# ถ้า chromedriver อยู่ใน PATH แล้ว ใช้ webdriver.Chrome() เฉยๆ ก็ได้
driver = webdriver.Chrome(executable_path=driver_path)
try:
# เปิดเว็บ Google
driver.get("https://www.google.com")
print("เปิด Google สำเร็จ!")
# หาช่องค้นหา ด้วย attribute name="q"
search_box = driver.find_element(By.NAME, "q")
search_box.send_keys("Selenium")
search_box.send_keys(Keys.RETURN) # กด Enter
print("ค้นหา Selenium สำเร็จ!")
# รอแป๊บนึง (อันนี้ไม่แนะนำให้ใช้ในงานจริงจังนะ)
# ควรใช้ Explicit Waits แทน
time.sleep(5)
# เช็คว่าผลลัพธ์การค้นหามาจริงไหม ลองหา text ที่คาดว่าจะเจอ
assert "Selenium" in driver.title # เช็คจาก title ของหน้าเว็บ
print("เจอคำว่า Selenium ใน Title ของหน้าเว็บผลลัพธ์")
except Exception as e:
print(f"เกิดข้อผิดพลาด: {e}")
# อาจจะ capture screenshot ตอน error ไว้ดูด้วยก็ดีนะ
# driver.save_screenshot("error_screenshot.png")
finally:
# ปิด browser ทุกครั้งเมื่อทำงานเสร็จ
driver.quit()
print("ปิดบราวเซอร์แล้ว")
โค้ดข้างบนมันจะเปิด Chrome ขึ้นมาเองเลยนะ แล้วก็จัดการกรอกข้อมูล กด Enter ให้เราเสร็จสรรพ เจ๋งดีใช่ไหมล่ะ
ปัญหาโลกแตก: Element หาไม่เจอ!
บ่อยโคตรๆ ใช่ปะ? ไอ้ NoSuchElementException เนี่ย! มันคือหา Element ที่เราอยากจะ Interact ด้วยไม่เจอไง สาเหตุหลักๆ ก็คือ Element นั้นอาจจะยังโหลดไม่เสร็จ หรือ Selector ที่เราใช้มันผิดพลาดเองแหละ
ตัวอย่าง Error:
selenium.common.exceptions.NoSuchElementException: Message: no such element: Unable to locate element: {"method":"css selector","selector":"[name='q']"}
วิธีแก้นอกจากเช็ค selector ดีๆ (จะใช้ Chrome DevTools ช่วยดู id, name, class, xpath, css selector ก็ได้นะ) แล้วคือ WebDriverWait นี่แหละ ช่วยชีวิตได้เยอะมากๆ มันคือการบอก Selenium ว่า "รอหน่อยนะ! รอจนกว่า Element นี้จะปรากฏขึ้นมา" ไม่ใช่รอแบบ time.sleep() มั่วๆ ที่บางที Element ก็มาไม่ทัน บางทีก็รอนานเกินไป.
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
# ...โค้ดเดิม...
try:
driver.get("https://www.google.com")
print("เปิด Google สำเร็จ!")
# ใช้ WebDriverWait รอจนกว่า Element ที่ชื่อ "q" จะปรากฏ
search_box = WebDriverWait(driver, 10).until(
EC.presence_of_element_located((By.NAME, "q"))
)
search_box.send_keys("Selenium")
search_box.send_keys(Keys.RETURN)
print("ค้นหา Selenium สำเร็จ!")
# ...ที่เหลือเหมือนเดิม...
except Exception as e:
print(f"เกิดข้อผิดพลาด: {e}")
finally:
driver.quit()
WebDriverWait(driver, 10) คือรอสูงสุด 10 วินาที ถ้าเกิน 10 วิแล้วยังไม่เจอ Element ที่เราหา มันก็จะ Error ออกมา ส่วน EC.presence_of_element_located คือรอจนกว่า Element นั้นจะอยู่ใน DOM (Document Object Model) ส่วน EC.visibility_of_element_located ก็มีนะ อันนั้นคือรอจนกว่าจะมองเห็นด้วยตาจริงๆ (อาจจะซ่อนไว้แต่ยังอยู่ใน DOM ก็ไม่ผ่าน)
สรุปแบบไม่เข้าข้าง!
คือมันก็ไม่ได้เพอร์เฟคไปซะทุกอย่างนะ บางที Element ก็เลื่อน, บางที Browser อัพเดทแล้ว WebDriver ดันไม่รองรับ ต้องมานั่งตามอัพเดทอีก แต่มันก็ช่วยให้เรามั่นใจได้เยอะขึ้นว่าหน้าเว็บของเรามันยังทำงานได้ตามที่ควรจะเป็นหลังจากการแก้ไขอะไรบางอย่าง. รวมๆ แล้วมันช่วยประหยัดเวลาชีวิตไปได้เยอะมาก ยิ่งถ้าเอาไปต่อยอดกับ CI/CD อย่างเช่น GitHub Actions ให้มันรัน Test อัตโนมัติทุกครั้งที่เรา Push โค้ดขึ้นไป นี่คือจะฟินกว่าเดิมอีกเยอะเลยนะ เชื่อดิ! ลองดูแล้วจะติดใจ.