Coding Gun

ทำ Test Automation ด้วย Selenium

Selenium คือเครื่องมือที่ควบคุมการทำงานของ Browser มีไว้สำหรับทำ automated testing ซึ่ง Selenium สามารถพํฒนาได้ภาษาต่างๆเหล่านี้

นอกจาก Automated Testing แล้ว selenium ยังสามารถนำไปใช้ในการทำ

  1. Robot Process Automation(RPA) สร้าง Bot เพื่อทำงานซ้ำๆแทนคน
  2. Web scraping เป็น Bot ที่เข้าไปเก็บข้อมูลบน Website ต่างๆ

แต่แน่นอนการทำ RPA และ Web scraping ไม่ได้เป็นตลาดใหญ่ของ Selenium เพราะ Selenium โ่ด่งดังขึ้นมาจากการทำ Automated Test ซึ่งถ้าคุณเข้าใจการทำงานของ Selenium ก็สามารถนำไปประยุกต์ใช้กับ RPA และ Web Scraping ได้ไม่ยาก

Selenium มี products ย่อยๆอยู่ 3 ตัวดังนี้

  1. Selenium IDE ทำหน้าที่บันทึกการทำงานของ UI(record)
  2. Selenium Webdriver เป็นเครื่องมือหลักที่เราใช้ควบคุม Browser
  3. Selenium Grid ช่วยให้ Selenium ทำงานเร็วขึ้น เนื่องจาก Selenium Grid จะทำแบบ Parallel(ทำพร้อมกันหลายๆงาน)

เราจะเลือกใช้ Selenium IDE หรือ Selenium Webdriver ในการสร้าง Test script แต่เราจะใช้ Selenium Grid ในการนำไป run test

Selenium ประกอบไปด้วยเครื่องมือย่อยๆ 3 ตัวดังนี้

  1. Selenium IDE
  2. Selenium Webdriver
  3. Selenium Grid

Selenium IDE

Selenium IDE คือ Browser extension ที่ติดตั้งเข้าไปใน Browser เพื่อบันทึกการทำงาน สามารถติดตั้งได้ทั้ง Chrome และ Firefox

ประโยชน์ที่เราได้จาก Selenium IDE คือ

  1. สามารถเขียน Test script ได้อย่างรวดเร็ว
  2. Selenium IDE ใช้การ Generate action ต่างๆที่เราทำออกมาเป็น Test script
  3. มี UI ที่สสามารถเริ่มต้นใช้งานได้ง่าย
  4. เหมาะสำหรับ QA ที่ไม่ชอบการเขียนโปรแกรม

ข้อเสียของ Selenium IDE คือ

  1. ความสามารถของ Selenium IDE มีจำกัด
  2. Test script ที่ generate ออกมามีความซ้ำซ้อน
  3. Test script ที่ได้อาจไม่สวยงาม อ่านยาก และแก้ไขได้ยาก
  4. Test script จะไม่สามารถสร้างเงื่อนไข หรือวน loop ได้

Selenium IDE
Chrome Selenium IDE

เราสามรถบันทึก Test script ออกมาโดยจะมีนามสกุลเป็น .side ซึ่งสามารถนำไปเปิดในเครื่องอื่นๆต่อได้

และนอกจากนี้เรายังสามารถ export Test Script ออกไปเป็นไฟล์ที่สามารถไป run ด้วย Test Runner ต่างๆ ดังนี้

  1. Python ที่ run ด้วย PyTest
  2. C# ที่นำไป run ด้วย XUnit
  3. C# ที่นำไป run ด้วย NUnit
  4. Java ที่นำไป run ด้วย JUnit
  5. JavaScript ที่นำไป run ด้วย Mocha
  6. Ruby ที่นำไป run ด้วย RSpec

Selenium Webdriver

เป็นการเขียน script เข้าไปควบคุมการทำงานของ browser โดยตรง ซึ่งก่อนจะควบคุม browser ได้ เราจำเป็นต้องติดตั้ง driver ก่อน เช่น ถ้าต้องการควบคุม Chrome เราต้องติดตั้ง Chromedriver

การเขียนคำสั่งต่างๆเข้าไปควบคุม browser เรียกว่า Web driver’s API ซึ่งข้อเสียของ Web driver’s API คือจะเขียนยากมี syntax ให้ต้องเรียนรู้อยู่เยอะมาก

ติดตั้ง Selenium Webdriver

สิ่งที่ต้องติดตั้งก่อนการใช้งาน Selenium Webdriver มีดังนี้

Selenium

  1. Test Runner และ Assertion Library ทำหน้าที่ run test script ซึ่งจะขึ้นอยู่กับภาษาที่เราเลือกมาเขียน เช่น ถ้าเขียนด้วย Python ก็จะต้องใช้ pytest ในการ run test script

    และใน Test runner ต้องการ Assertion Library ซึ่งบางตัวจะติดตั้งมาด้วยกัน บางตัวอาจต้องมีการติดตั้ง Library แยกต่างหาก

  2. Web Driver Library เป็น Library สำหรับคำสั่งที่ต่างๆที่เราจะใช้เขียน Test script ดูตัวอย่างการเขียน Selenium Webdriver ด้วย Python

  3. Driver เป็น driver สำหรับควบคุมการทำงานของ Browser ซึ่งต้องอ้างอิงตาม Browser ที่เราจะใช้ทดสอบ ซึ่งเราสามารถ Download Selenium Webdriver ได้ตาม Link ด้านล่างนี้

    ปัญหาของการใช้งาน Selenium คือต้องตาม update driver ทุกครั้งที่ browser update ซึ่งหลังจาก Selenium 4.6 เป็นต้นไป เราจะมี Selenium Manager คอยดูแลการ install และ update driver ให้เรา

    ข้อควรระวัง ถ้าเรา add PATH ของ driver ไว้ใน Environment Variable(เราติดตั้ง driver เอง) Selenium Manager จะไม่ทำงาน เราต้องคอย update driver เองเหมือนเดิม และอีกปัญหาที่เราจะเจอบ่อยๆคือ เครื่องที่ run test ต้องออก internet ได้ และไม่ถูก block การ download ด้วย firewall

    ข้อแนะนำ ถ้ามี selenium driver ที่ติดต้ังมาก่อนหน้านี้ให้ remove ออกแล้วให้ Selenium Manager คอยดูแลเรื่อง version ให้เรา

    Selenium Web Driver Architecture
    Selenium Web Driver Architecture

การติดตั้ง Selenium นั้นจะมีขั้นตอนเยอะกว่า Automated Testing Framework ตัวอื่นๆ อย่าง Playwright และ Cypress เพราะต้องมีการติดตั้ง Driver นี่แหละ นี่เป็นสิ่งที่ Selenium พยายามปรับตัวเพื่อแข่งขันกับ Playwright และ Cypress

Playwright vs Selenium
เปรียบเทียบความง่ายในการติดต้ังของ Playwright และ Selenium

เขียน Selenium Webdriver ด้วย Python

Python เป็นหนึ่งในภาษาที่ถูกนำมาใช้เขียน Test script มากที่สุด และ Selenium ก็ support python เช่นเดียวกับ Framework อื่นๆ ในตัวอย่างนี้เราจะเขียน test script เพื่อควบคุมการทำงานของ browser ผ่านทาง Web Driver ด้วย python แบบเบื้องต้นกัน

เริ่มจากการเขียน Test script จะมีโครงสร้างดังนี้

  1. import webdriver เข้ามาใช้งาน

    import webdriver
    
  2. load webdriver ขึ้นมาด้วยคำสั่ง

    driver = webdriver.Chrome()
    
  3. เข้าไปยังหน้า Web ที่ต้องการทดสอบ ด้วยคำสั่ง

    driver.get("https://codinggun.com")
    
  4. รอจนกว่าหน้า Web จะ load เสร็จด้วยคำสั่ง Wait

    driver.implicitly_wait(0.5)
    

    จุดนี้จะต้องกำหนดค่าให้เหมาะสมกับระยะเวลาที่ใช้ในการ load หน้า web ถ้า net เราช้าต้องใช้เวลาในการ load หน้า web นานจะต้องกำหนด implicitly_wait ให้มากขึ้น

    อ่านการใช้คำสั่ง Wait ใน Selenium ต่อได้ที่นี่

  5. ค้นหา element ที่ต้องการด้วยคำสั่ง

    btn = driver.find_element(By.ID, "btnSubmit")
    

    ดูคำสั่งที่ใช้ในการค้นหา Web elements อื่นๆได้ที่นี่

  6. ส่งคำสั่งเข้าไปควบคุมการทำงานของ Element นั้น

    btn.click()
    

    ดูคำสั่งที่ใช้ควบคุมการทำงานของ browser อื่นๆต่อได้ที่นี่

  7. จบการทำงานของ Webdriver ด้วยคำสั่ง

    driver.quit()
    

สุดท้ายแล้วเราจะได้ตัวอย่าง Test script ที่เขียนด้วย python หน้าตาแบบนี้

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
import webdriver

driver = webdriver.Chrome()
driver.get("https://codinggun.com")
driver.implicitly_wait(0.5)

btn = driver.find_element(By.XPATH, "/html/body/header/ul/li[1]/a")
btn.click()

driver.quit()

การใช้คำสั่ง Wait ใน Selenium

การใช้คำสั่ง Wait เป็นสิ่งที่ต้องทำความเข้าใจ เพราะเป็นสิ่งที่จะทำให้เกิด flaky test(การทดสอบที่ได้ผลลัพธ์แตกต่างกันในแต่ละครั้งที่ run test)

ใน Selenium จะแบ่งประเภทของการ Wait ออกเป็น 2 ประเภท ดังนี้

  1. Implicit Wait Selenium จะ delay การทำงานออกไปตามระยะเวลาที่เรากำหนด โดยจะไม่ได้สนใจว่า Elements ที่เราต้องการนั้นถูก load ขึ้นมารึยัง ตัวอย่างของ implicit wait จะเป็นดังนี้

     driver.implicitly_wait(2)
    

    ค่า default ของ implicitly_wait จะเป็น 0 นั่นหมายความว่าถ้าเราไม่กำหนด Implicit wait หรือ Explicit wait ใน script ของเรา Selenium จะเข้าไปค้นหา Web elements ด้วยคำสั่ง find_element ทันที ซึ่งจะทำให้เกิด error เพราะ Web elements นั้นจะ load ไม่ทัน

  2. Explicit Wait Selenium จะทำการ delay การทำงานพร้อมกับการตรวจสอบ element ที่เราค้นหา โดยจะวน loop ไปเรื่อยๆจนกว่า element ที่เราต้องการจะถูก load ขึ้นมา ตัวอย่างของ Explicit Wait จะเป็นดังนี้

    1
    2
    3
    4
    5
    6
    
    btn = driver.find_element(By.ID, "btnSubmit")
    
    wait = WebDriverWait(driver, timeout=2)
    wait.until(lambda d : btn.is_displayed())
    
    btn.click()
    

    code หลังจากบรรทัด wait_until จะถูก run ก็ต่อเมื่อปุ่มที่มี ID เป็น btnSubmit ถูก load ขึ้นมา

ข้อควรระวัง ไม่ควรใช้ Implicit และ Explicit waits ร่วมกัน ควรเลือกใช้แค่ตัวใดตัวหนึ่งเท่านั้น

ค้นหา Web Elements

การทดสอบเราจำเป็นต้องใช้ Locators ในการค้นหา Web element ที่ต้องการเพื่อนำไปใส่ข้อมูล หรือ trigger events ต่างๆ เช่น click ปุ่ม submit

ใน Selenium สามารถใช้ locators ได้หลายรูปแบบ ซึ่งจะแบ่งออกเป็นรูปแบบต่างๆ ดังนี้

ตัวอย่าง ของ HTML ที่เราจะใช่้ทำการทดสอบเป็นแบบนี้

<button id="btnSubmit" name="btnSubmit" class="btn-mb-2">
    Submit
</button>
  1. ID ถ้าต้องการหา web element ด้วย ID เราจะใช้คำสั่ง

    WebDriver driver = new ChromeDriver();
    btn = driver.find_element(By.ID, "btnSubmit")
    
  2. Name ถ้าต้องการหา web element ด้วย attribute name เราจะใช้คำสั่ง

    WebDriver driver = new ChromeDriver();
    btn = driver.find_element(By.NAME, "btnSubmit")
    
  3. Tag Name ถ้าต้องการค้นหา web element ตามชื่อ tag ให้ใช้คำสั่ง

    WebDriver driver = new ChromeDriver();
    btn = driver.find_element(By.TAG, "button")
    
  4. Class Name ถ้าต้องการค้นหา web element ด้วย CSS Class เราจะใข้คำสั่ง

    WebDriver driver = new ChromeDriver();
    btn = driver.find_element(By.CLASS_NAME, "btn-mb-2")
    
  5. CSS Selector ถ้าเราต้องการค้นหา web element ด้วย CSS selector เราต้องใช้คำสั่ง

    WebDriver driver = new ChromeDriver();
    btn = driver.find_element(By.CSS_SELECTOR, "#btnSubmit")
    

    ในตัวอย่างนี้จะค้นหา html tag ที่มี id เป็น btnSubmit

  6. XPath Selector ถ้าเราต้องการค้นหา web element ด้วย xpath เราจะใช้คำสั่ง

    WebDriver driver = new ChromeDriver();
    btn = driver.find_element(By.XPATH, "//button[text()='Click Me'])
    

    ในตัวอย่างนี้จะค้นหา tag button ที่มีข้อความว่า Click Me

    ในการทำงานจริงเราจะเข้าไปที่ Chorme Development Tools และ click ขวาบน Element ที่เราต้องการแล้วเลือก Copy XPath ดังรูป

    Copy XPath from chrome development tools
    Copy XPath จาก chrome development tools

  7. Link Text และสำหรับ Link text เราจะใช้ค้นหา anchor tag ที่มีข้อความที่เรากำหนด ยกตัวอย่างถ้าเรามี HTML แบบนี้

    <div>
        <a href="...">Click Me</a>
        <a href="...">Click This Text</a>
    </div>
    

    เราจะต้องเขียน python เพื่อค้นหา element ที่เราต้องการแบบนี้

    WebDriver driver = new ChromeDriver();
    btn = driver.find_element(By.LINK_TEXT, "Click Me")
    

    ถ้าเราใช้ Link Text ข้อความที่ค้นหาต้องถูกต้องแบบเป๊ะๆเลย

  8. Partial Link Text จะเหมือนกับ Link Text แต่ว่าใช้ส่วนใดส่วนหนึ่งของข้อความในการค้นหา(substrings) จากตัวอย่าง HTML ด้านบน เราจะเขียน python เพื่อค้นหา element ออกมาแบบนี้

    WebDriver driver = new ChromeDriver();
    btn = driver.find_element(By.PARTIAL_LINK_TEXT, "Click")
    

    ในตัวอย่างนี้เราจะได้่ elements ออกมา 2 elements ทั่้ง Click Me และ Click This Text

ทำงานกับ Web Elements

หลังจากที่เราได้ Element ที่ต้องการมาแล้วเราจะต้อง สั่งให้มันทำงานด้วยคำสั่ง

Click

ถ้าต้องการให้ปุ่ม Click Me ถูก click เราจะต้องเขียน script แบบนี้

driver.find_element(By.ID, "btnSubmit").click()

Clear

ถ้าเราต้องการ clear input ก่อนจะกรอกข้อมูลลงไป เราจะเขียน script แบบนีั้

driver.find_element(By.NAME, "email").clear()

Send Keys

ถ้าเป็น tag input ที่เราต้องกรอกค่าต่างๆลงไปเราจะเขียน script แบบนี้

driver.find_element(By.NAME, "email").send_keys("admin@localhost.dev" )

Selenium Grid

Selenium Grid คือเครื่องมือที่ช่วยให้เรา run Test Script พร้อมๆกันแบบคู่ขนาน(parallel) เพราะปัญหาของการทำ UI Testing คือความช้า ถ้าเราต้องการทดสอบหลายๆ workflow พร้อมๆกัน เราก็จะใช้ Selenium Grid มาช่วยแตก process แล้วกระจายไปยังเครื่องต่างๆ(Nodes)

และนอกจากความเร็วที่เราจะได้จาก Selenium Grid แล้วเรายังสามารถแยกการทดสอบด้วย Browser หลายๆตัว หรืออาจเป็นการทดสอบ Browser ตัวเดียวกันแต่หลาย version ก็ได้

ซึ่ง Selenium Grid จะแบ่งออกเป็น 2 components คือ

  1. Hub เป็นตัวกระจายงานออกไปยัง Node ต่างๆ ทำหน้าที่เป็น controller คอยควบคุมการทำงาน ซึ่งใน 1 grid จะมี 1 hub เท่านั้น
  2. Nodes เครื่องที่ใช้ทดสอบ จะมีได้หลายตัว(เป็น VM หรือ Container) และหลาย environments ขึ้นอยู่กับสิ่งที่เราต้องการทดสอบ

Selenium Grid Components
Hub และ Nodes ใน Selenium Grid

Client ที่อยู่ใสรูปอาจเป็น Test script ที่เขียนด้วย python,java,c#,javscript,ruby,php หรืออาจเป็น task งานที่อยู่ใน CI/CD pipelines อย่าง Jenkins, Gitlab CI หรือ Azure DevOps ก็ได้

การ deploy Node สำหรับ run test เราจะเลือกใช้ Container หรือ Virtual Machine(VM) ก็ได้

โดยสรุปข้อดีของการใช้ Selenium Grid คือ

  1. กระจายงาน(task) ออกไปยัง Node ต่างๆ
  2. ทดสอบแบบเดียวกันบน Browser หลายๆตัวพร้อมๆกัน
  3. ทดสอบแบบเดียวกันบน Browser เดียวกันแต่หลาย version

อีกทางเลือกนึงที่เราสามารถนำมาใช้แทน Selenium Grid คือ CI/CD pipeline ซึ่งจะสามารถแตก task ได้ง่ายกว่า รวมทั้งยัง support container อยู่แล้ว ทีมไหนที่มี CI/CD pipeline แนะนำให้แตก Task ใน Pipeline แทนการใช้งาน Selenium Grid

Robot Framework

ในกรณีที่เราใช้ Robot Framework เราจะต้องติดตั้ง SeleniumLibrary เพื่อให้สามารถใช้ keyword ต่างๆควบคุมการทำงานของ browser ได้

ตัวอย่างการเขียน Robot script ด้วย SeleniumLibrary

1
2
3
4
5
6
*** Test Cases ***
User can goto codinggun website
    [Documentation]  Open codinggun.com and close broser
    [Tags]  Smoke
    Open Browser  http://www.codinggun.com  chrome
    Close Browser

อ่านวิธีการใช้ Robot Framework ต่อได้ที่นี่

อ่านบทความอื่นๆเกี่ยวกับการทำ Automated Test ได้ที่

Phanupong Permpimol
Follow me

Software Engineer ที่เชื่อในเรื่องของ Process เพราะเมื่อ Process ดี Product ก็จะดีตาม ปัจจุบันเป็นอาจารย์และที่ปรึกษาด้านการออกแบบและพัฒนา Software และ Web Security