Robot framework เรียนให้รู้ ตอน 2

Phai Panda
9 min readFeb 6, 2020

--

ดูสิว่าร้านขายก๋วยเตี๋ยวใน web application นี้ทำอะไรได้บ้าง แล้วใช้ Robot framework มาจัดการ Test cases ได้อย่างไร

https://www.wongnai.com/listings/must-try-beef-noodles-in-bangkok

ความเดิมจากตอนที่แล้ว

Requirement 1/10

มาดู requirement ครั้งที่ 1/10 ของเจ้าของร้านกันหน่อย

  1. อยากให้มีชื่อร้านว่า ก๋วยเตี๋ยวพูนใจ (title name)
  2. อยากให้มีรายการก๋วยเตี๋ยว (ordered list) อย่างน้อย 3 รายการปรากฏที่หน้าแรก (home page) และมีได้สูงสุดไม่เกิน 5 รายการ
  3. รายการก๋วยเตี๋ยว (ordered list) ในข้อ 2. จะเพิ่มขึ้นก็ต่อเมื่อลูกค้ากดปุ่ม “สั่ง”

เพื่อนๆต้องทราบก่อนว่าวิธีการที่ผมฝึกฝนนี้จะรับ requirement จากลูกค้าครั้งละ 3 ถึง 5 ข้อสลับกับการนำไปเขียนเป็น web application แล้วส่งมอบให้ลูกค้าพร้อม Robot framework ที่ครอบคลุม (แทบ) ทุกกรณีใน requirement ดังกล่าว

เอาล่ะ เรามาเริ่ม config โปรเจกต์กันต่อเลยนะครับ

Theme & CSS

  • ตัว UI จะใช้ Angular Material
  • CSS ใช้ Bootstrap 4

Angular Material ทุกอย่างพร้อมสรรพแค่ขยับปลายนิ้ว ทำตามขั้นตอนติดตั้งเลยครับ ง่ายมากๆ

ng add @angular/material
  • เลือก Indigo/Pink theme
  • HammerJS => Y
  • Browser Animations => Y

เสร็จแล้วต่อด้วยติดตั้ง Bootstrap

npm install bootstrap

หลังจากนั้นไฟล์ package.json ต้องมี

Angular Material Theme & CSS Bootstrap

config Bootstrap ต่อเลย เปิดไฟล์ angular.json มองหาส่วนที่เขียนว่า

projects > angular-robot > architect > build > options > styles

แล้วยัด path ของ Bootstrap ลงไป ลากมาตั้งแต่ node_modules เลยนะ (อย่าได้ลืมเครื่องหมาย , คั่นระหว่าง property ล่ะ)

"./node_modules/bootstrap/dist/css/bootstrap.css"

หลังการแก้ไขค่า config ทุกครั้งจะต้องหยุด server ก่อน (ถ้าเกิดว่า run อยู่) แล้วรันใหม่อีกครั้ง

หมายเหตุ control + c หยุด server ก่อน จากนั้นรันใหม่ด้วย ng s

เรามาดูว่า Angular Material และ Bootstrap พร้อมใช้งานไหม อาจจะสังเกตจาก tag และ CSS ต่อไปนี้ว่ามันแสดงผลและปรากฏออกมาได้ตามที่ใจนึกไหม

  • <mat-toolbar></mat-toolbar>
  • คลาส container

เปิดไฟล์ app.module.ts แล้วเพิ่ม MatToolbarModule

import {MatToolbarModule} from '@angular/material/toolbar';...imports: [...  MatToolbarModule
],

เปิดไฟล์ app.component.html แล้วแก้ไขให้เป็นดังนี้

app.component.html

เปิดไฟล์ app.component.css แล้วแก้ไขให้เป็นดังนี้

app.component.css

ผลลัพธ์

ทดสอบ Angular Material & Bootstrap ใช้งานได้เป็นปกติ

เอาล่ะมาดูที่ requirement กันครับ

เพิ่มรายละเอียดให้หน้า Home

ต้องการชื่อร้านว่า ก๋วยเตี๋ยวพูนใจ เปิดไฟล์ app.component.ts แก้ไขค่า title

export class AppComponent {title = 'ก๋วยเตี๋ยวพูนใจ';}

เพิ่มปุ่ม “สั่ง” (order) เปิดไฟล์ app.component.html

...<div class="d-flex justify-content-between">  <div class="ordered">item 1</div>  <div class="ordered">item 2</div>  <div class="ordered">item 3</div></div><div class="mt-2">  <button mat-raised-button color="primary">สั่ง</button></div>...

อย่าลืมเพิ่ม import ส่วน button tag ของ Angular Material เปิดไฟล์ app.module.ts

import {MatToolbarModule} from '@angular/material/toolbar';import {MatButtonModule} from '@angular/material/button';...imports: [...  MatToolbarModule,  MatButtonModule,],

ผลลัพธ์

ปรับแต่งตาม requirement contents

เอาล่ะน่าจะพอแล้ว ถัดไปเรามาลุย Robot framework กัน

Basic Selenium2Library

จริงๆต้อง update เพื่อนๆก่อนว่า Selenium2Library นั้นได้เปลี่ยนชื่อเป็น SeleniumLibrary เฉยๆไปแล้วตั้งแต่มันเวอร์ชัน 3.0

เมื่อเราใช้ pip มาจัดการ package ตั้งแต่แรกเริ่ม เราสามารถใช้คำสั่งนี้ดูรายละเอียดได้ครับ

pip freeze
selenium2library เวอร์ชัน 3 แล้ว

แน่นอนว่าเพื่อดูแลความเข้ากันได้กับเวอร์ชันก่อนหน้านี้ (จะได้ไม่ต้องแก้โค้ด) แม้เราจะเรียกคำสั่ง Selenium2Library ที่เวอร์ชัน 3.0 มาใช้งานก็คือการเรียกคำสั่ง SeleniumLibrary เฉยๆนั่นเอง

จากข้อมูลนี้ลองเปลี่ยนบรรทัด import จากเดิมเรียกใช้ Selenium2Library เป็น SeleniumLibrary แล้วรันครับ ซึ่งโค้ดด้านล่างนี้ผมสั่งเพิ่มให้มันไปเปิด browser Chrome ด้วยเลย

*SettingsLibrary     SeleniumLibrary
*Test CasesOpen Firefox Browser Open Browser http://localhost:4200 firefoxOpen Chrome Browser Open Browser http://localhost:4200 chrome

ผล

ผ่านการทดสอบ

สรุปได้ว่า Selenium2Library ที่เวอร์ชัน 3.0 นี้เป็นแค่เสื้อคลุมบางๆ (wrapper) แก่ SeleniumLibrary

เอาล่ะมาดูพื้นฐานกัน!

มันประกอบด้วย 4 ส่วนสำคัญ ได้แก่

  • Settings
  • Test Cases
  • Keywords
  • Variables

Settings

อธิบายว่าจะใช้ไลบรารีตัวไหน คำสั่งอ้างอิงไลบรารีที่ต้องการคือ Library ตามด้วยชื่อไลบรารีนั้น นอกจากนี้ยังมีคำสั่ง Test Setup และ Test Teardown ไว้เพื่อสั่งว่าก่อนเริ่ม test case และจบ test case จะให้ทำอะไร

เอาเท่านี้ก่อน

Test Cases

อธิบาย test case ทั้งหมดที่ต้องการให้ Robot ทำงานให้ ตัวอย่างเช่น

Open Firefox Browser เป็นชื่อ test case ตั้งอะไรก็ว่าไป

Open Browser อันนี้เป็น key word ซึ่งต้องเขียนให้ถูก แต่มันไม่ถือสาจะใช้พิมพ์เล็กหรือพิมพ์ใหญ่ผสมกันได้หมด

รูปแบบสำหรับ 1 test case คือ

ชื่อ test case + คำสั่งต่างๆ (keywords)

โดยที่คำสั่งต่างๆจะต้องเขียนให้ห่างจาก ชื่อ test case อย่างน้อย 2 ช่องว่าง

เช่น

Open Firefox Browser
Open Browser http://localhost:4200 firefox

หรือ

Open Firefox Browser  open browser    http://localhost:4200   firefox

โดยทั่วไปแล้วแต่ละ test case จะแยกเป็นอิสระจากัน หมายความว่าถ้า test case ก่อนหน้าพัง test case หลังก็ยังทำงานต่อไป

เอาเท่านี้ก่อน

Keywords

ก็คือคำสั่งต่างๆใน SeleniumLibrary อ้างอิงจากที่นี่

Add Cookie · Add Location Strategy · Alert Should Be Present · Alert Should Not Be Present · Assign Id To Element · Capture Page Screenshot · Checkbox Should Be Selected · Checkbox Should Not Be Selected · Choose Cancel On Next Confirmation · Choose File · Choose Ok On Next Confirmation · Clear Element Text · Click Button · Click Element · Click Element At Coordinates · Click Image · Click Link · Close All Browsers · Close Browser · Close Window · Confirm Action · Create Webdriver · Current Frame Contains · Current Frame Should Contain · Current Frame Should Not Contain · Delete All Cookies · Delete Cookie · Dismiss Alert · Double Click Element · Drag And Drop · Drag And Drop By Offset · Element Should Be Disabled · Element Should Be Enabled · Element Should Be Focused · Element Should Be Visible · Element Should Contain · Element Should Not Be Visible · Element Should Not Contain · Element Text Should Be · Execute Async Javascript · Execute Javascript · Focus · Frame Should Contain · Get Alert Message · Get All Links · Get Cookie · Get Cookie Value · Get Cookies · Get Element Attribute · Get Element Count · Get Element Size · Get Horizontal Position · Get List Items · Get Location · Get Locations · Get Matching Xpath Count · Get Selected List Label · Get Selected List Labels · Get Selected List Value · Get Selected List Values · Get Selenium Implicit Wait · Get Selenium Speed · Get Selenium Timeout · Get Source · Get Table Cell · Get Text · Get Title · Get Value · Get Vertical Position · Get WebElement · Get WebElements · Get Window Handles · Get Window Identifiers · Get Window Names · Get Window Position · Get Window Size · Get Window Titles · Go Back · Go To · Handle Alert · Input Password · Input Text · Input Text Into Alert · Input Text Into Prompt · List Selection Should Be · List Should Have No Selections · List Windows · Location Should Be · Location Should Contain · Locator Should Match X Times · Log Location · Log Source · Log Title · Maximize Browser Window · Mouse Down · Mouse Down On Image · Mouse Down On Link · Mouse Out · Mouse Over · Mouse Up · Open Browser · Open Context Menu · Page Should Contain · Page Should Contain Button · Page Should Contain Checkbox · Page Should Contain Element · Page Should Contain Image · Page Should Contain Link · Page Should Contain List · Page Should Contain Radio Button · Page Should Contain Textfield · Page Should Not Contain · Page Should Not Contain Button · Page Should Not Contain Checkbox · Page Should Not Contain Element · Page Should Not Contain Image · Page Should Not Contain Link · Page Should Not Contain List · Page Should Not Contain Radio Button · Page Should Not Contain Textfield · Press Key · Radio Button Should Be Set To · Radio Button Should Not Be Selected · Register Keyword To Run On Failure · Reload Page · Remove Location Strategy · Select All From List · Select Checkbox · Select Frame · Select From List · Select From List By Index · Select From List By Label · Select From List By Value · Select Radio Button · Select Window · Set Browser Implicit Wait · Set Focus To Element · Set Screenshot Directory · Set Selenium Implicit Wait · Set Selenium Speed · Set Selenium Timeout · Set Window Position · Set Window Size · Simulate · Simulate Event · Submit Form · Switch Browser · Table Cell Should Contain · Table Column Should Contain · Table Footer Should Contain · Table Header Should Contain · Table Row Should Contain · Table Should Contain · Textarea Should Contain · Textarea Value Should Be · Textfield Should Contain · Textfield Value Should Be · Title Should Be · Unselect All From List · Unselect Checkbox · Unselect Frame · Unselect From List · Unselect From List By Index · Unselect From List By Label · Unselect From List By Value · Wait For Condition · Wait Until Element Contains · Wait Until Element Does Not Contain · Wait Until Element Is Enabled · Wait Until Element Is Not Visible · Wait Until Element Is Visible · Wait Until Page Contains · Wait Until Page Contains Element · Wait Until Page Does Not Contain · Wait Until Page Does Not Contain Element · Xpath Should Match X Times

สนใจคำสั่ง (keyword) ไหนก็ไปอ่านรายละเอียดการใช้งานครับ

Variables

ใครที่เคยเขียนโปรแกรมมาก่อนนี่จะง่ายมาก มันก็คือการประกาศตัวแปรเพื่อนำไปใช้งานในส่วนอื่นๆ โดยที่ชื่อของตัวแปรนั้นต้องอยู่ในเครื่องหมาย ${} เช่น

${CREDENTIALS}

ชื่อที่ตั้งนี้จะใช้พิมพ์เล็กหรือใหญ่ก็ได้ ซึ่งรูปแบบการตั้งชื่อตัวแปรนั้นเป็นไปตาม Robot framework variable declaration

เช่น

${NAME}         Robot Framework
${VERSION} 2.0
${ROBOT} ${NAME} ${VERSION}

บางคนอาจมีคำถาม ต้องเว้นไว้ 2 ช่องว่างอีกไหม? (ผมขำ) ตอบเลยว่าเว้นไว้เหมือนเดิมจ้า

เอาเท่านี้ก่อน

Time to Robot writing

มาๆเขียน automated test กันได้แล้วล่ะ เปิดไฟล์ hello.robot

Test Setup vs Test Teardown

เริ่มจากขอลองใช้ Test Teardown สั่งให้ปิด browser หลังจากจบการทดสอบ

เรียกคำสั่ง Test Teardown ใน Settings

อ่อ ถ้าเพื่อนๆถามว่าทำไม VS Code ผมไม่มี suggestion เหมือนของพี่ อย่างนั้นให้ติดตั้ง plugin ตัวนี้ครับ

Robot framework intellisense
*SettingsLibrary         SeleniumLibraryTest Teardown   Close Firefox Browser*Test Cases
Open Firefox Browser
Open Firefox Browser*KeywordsClose Firefox Browser Close Browser

Test Teardown จะเรียก keyword ที่ชื่อ Close Firefox Browser (ชื่อนี้เราตั้งเอง) หรือถ้าพูดในภาษาโปรแกรมมิ่งธรรมดาคือ คำสั่ง Test Teardown จะเรียกฟังก์ชันชื่อ Close Firefox Browser ให้ทำงาน Close Browser

ถัดไปเราจะทดลองเรียก Test Setup เพื่อให้เปิด browser แก่เรา

*SettingsLibrary         SeleniumLibraryTest Setup      Open Firefox BrowserTest Teardown   Close Firefox Browser*Test Cases
*KeywordsClose Firefox Browser Close BrowserOpen Firefox Browser Open Browser http://localhost:4200 firefox

ขณะนี้เราได้สร้าง keyword ขึ้นมาเอง 2 keywords แล้ว (2 functions) ชื่อ

  • Close Firefox Browser
  • Open Firefox Browser

ทว่าจะยังรันไม่ผ่าน เพราะ

[ ERROR ] Suite ‘Hello’ contains no tests.

มันแจ้งว่าอย่างน้อยส่วนของ Test Cases จะต้องมีอย่างน้อย 1 test case

Title Name Test Case

ความคาดหวัง: ร้านนี้ควรมีชื่อว่า ก๋วยเตี๋ยวพูนใจ

เพิ่มส่วนของ Test Cases

*Test CasesTitle Name Should Be ก๋วยเตี๋ยวพูนใจ  Element Text Should Be      //mat-toolbar    ก๋วยเตี๋ยวพูนใจ
ผ่าน!

ทีนี้สมมติว่าวันหนึ่ง ดันมีมือดีมาเปลี่ยนชื่อร้านนี้โดยไม่บอกใคร (เขาทำไปเพื่ออะไรนะ?) จากร้าน ก๋วยเตี๋ยวพูนใจ เปลี่ยนเป็น ยายน้อยโพทะยาน ดังนี้

export class AppComponent {  title = 'ยายน้อยโพทะยาน';}

แล้วปรากฏว่า Robot มาทำงาน เราก็จะได้รู้ว่าสิ่งแปลกได้เกิดขึ้นแล้ว

ไม่ผ่าน

Ordered List

เขาว่าอย่างน้อยต้องมี 3 รายการก๋วยเตี๋ยวที่ได้สั่งไปแล้วปรากฏให้เห็นเสมอ แต่ก็ไม่ให้เกิน 5 รายการ

*Test CasesTitle Name Should Be ก๋วยเตี๋ยวพูนใจ  Element Text Should Be      //mat-toolbar    ก๋วยเตี๋ยวพูนใจOrdered List Should Show Greater Than Or Equal To 3 And Less Than Or Equal To 5  ${count}=  Get Element Count    css:div.ordered  Should Be True                  ${count} >= 3  Should Be True                  ${count} <= 5
ผ่าน

สมมติว่า logic ของโปรแกรมเมอร์ผิดพลาด ดันไปเพิ่มของในรายการ show case นี้เป็น 6 ชิ้น ดังนี้

<div class="d-flex justify-content-between">  <div class="ordered">item 1</div>  <div class="ordered">item 2</div>  <div class="ordered">item 3</div>  <div class="ordered">item 4</div>  <div class="ordered">item 5</div>  <div class="ordered">item 6</div></div>

แล้วปรากฏว่า Robot มาทำงาน

ไม่ผ่าน

หรือไปลดของในรายการ show case นี้ต่ำกว่า 3 ชิ้น ดังนี้

<div class="d-flex justify-content-between">  <div class="ordered">item 1</div>  <div class="ordered">item 2</div></div>

แล้วปรากฏว่า Robot มาทำงาน

ไม่ผ่าน

Clicked Order Button

กดปุ่ม สั่ง แล้วรายการก๋วยเตี๋ยวจะต้องเพิ่มขึ้น

อันนี้มันก็แปลกๆนะ แต่ใช่ว่าทำไม่ได้ ความคิดคือ ก่อนกดปุ่มให้นับจำนวนรายการไว้ก่อน และหลังกดปุ่มจึงนับจำนวนรายการอีกครั้ง มากกว่า 1 จึงถือว่าถูกต้อง

เรามาเขียนโค้ดเพิ่มเพื่อให้รายการก๋วยเตี๋ยวนี้ dynamic ก่อนนะครับ

  • เปลี่ยน static เป็น dynamic ด้วย *ngFor
  • กำหนด ordered list มีชนิดข้อมูลเป็น array

ไฟล์ app.component.html

<div class="d-flex justify-content-between" *ngFor="let order of orderedList">  <div class="ordered">{{order.name}}</div></div>

ไฟล์ app.component.ts

export class AppComponent {  title = 'ก๋วยเตี๋ยวพูนใจ';  orderedList = [    { name: 'item1' },    { name: 'item2' },    { name: 'item3' }  ];}

แล้วให้ Robot รัน cases เดิมให้ผ่านก่อน

ผ่าน

แก้ไขต่อได้

ไฟล์ app.component.html เพิ่ม click event ให้กับปุ่มสั่ง ตั้งชื่อว่า order

<div class="mt-2">  <button mat-raised-button color="primary" (click)="order()">สั่ง</button></div>

ไฟล์ app.component.ts เพิ่มเมธอด order และ logic

order() {  const newOrder = {    name: 'item4'  };  this.orderedList.push(newOrder);}

มาเขียน test case นี้ในส่วนของ Robot กัน

Ordered List Should Increase 1 After Click Order Button  ${beforCount}=  Get Element Count    css:div.ordered  Click Button    //button  ${afterCount}=  Get Element Count    css:div.ordered  Should Be True                  ${afterCount} - ${beforCount} == 1
ผ่าน!

แต่ถ้าสมมติว่า logic ไม่ดี กดปุ่มสั่งแล้วเบิ้ลคู่ เช่น

order() {  const newOrder = {    name: 'item4'  };  this.orderedList.push(newOrder);  this.orderedList.push(newOrder); // double!}

ผล

ไม่ผ่าน

เรียบร้อยเป็นว่าสำเร็จแล้วสำหรับ requirement 1/10

Locating elements

เพื่อนๆจะสังเกตเห็นว่ามีโค้ดอยู่หลายส่วนที่เราไม่เข้าใจ ต้องอาศัยการอ่านทำความเข้าใจหรือแสวงหาตัวอย่างอื่นๆในอินเตอร์เน็ตประกอบ เช่นคำสั่งนี้

Click Button    //button

เพื่อนๆมือใหม่อาจเดาได้ว่า สั่งให้มันกดปุ่ม ใช่แล้วครับ เราสั่งให้มันกดปุ่ม แล้วรู้ไหมสัญลักษณ์ //button นี้หมายถึงอะไร เป็นต้น

พารามิเตอร์ส่วนใหญ่ของ SeleniumLibrary เขาต้องการ locator หมายถึงที่ที่ element ตัวนี้แสดงตนอยู่ในไฟล์ .html ไม่ว่าจะเป็นรูปแบบของ id, name, tag, css หรืออื่นๆ เพื่อนๆสามารถอ่านรายละเอียดได้ที่หัวข้อ Locating elements ของ SeleniumLibrary document ครับ

โค้ดทั้งหมด

เอาล่ะลองทำดูเราทำได้

อ่านต่อตอนที่ 3

อ้างอิง

https://www.w3schools.com/xml/xpath_syntax.asp

https://www.guru99.com/xpath-selenium.html

--

--

No responses yet