#การรัน Robot Framework ด้วย Docker และการรันแบบขนานด้วย Pabot

Robot Framework สามารถทำงานใน Docker Container เพื่อให้สภาพแวดล้อมการทดสอบมีความสม่ำเสมอ (reproducible) ระหว่างเครื่องนักพัฒนา, Test Server และ CI/CD Pipeline ส่วน Pabot เป็น parallel executor สำหรับ Robot Framework ที่ช่วยกระจาย Test Suite หรือ Test Case ไปทำงานพร้อมกันหลาย process เพื่อลดเวลารวมของการทดสอบ

แนวคิดโดยรวมคือ

Host / CI Runner
      |
      v
Docker Container
      |
      +-- Robot Framework
      +-- Pabot
      +-- Test Libraries
      |
      +-- Worker 1 --> Suite A
      +-- Worker 2 --> Suite B
      +-- Worker 3 --> Suite C
      +-- Worker 4 --> Suite D
      |
      v
results/
  ├── output.xml
  ├── log.html
  └── report.html

info-robot-framework-docker-pabot

#1. โครงสร้าง Project

ตัวอย่างโครงสร้างที่เหมาะสำหรับเริ่มต้น

robot-docker/
├── Dockerfile
├── compose.yaml
├── requirements.txt
├── tests/
│   ├── login.robot
│   ├── product.robot
│   └── checkout.robot
└── results/

#2. สร้าง requirements.txt

robotframework
robotframework-pabot
robotframework-requests

หากทดสอบ Web UI ด้วย Selenium สามารถเพิ่ม

robotframework-seleniumlibrary

ควร pin version ของ dependencies ในงานจริง เพื่อให้ Docker Image แต่ละ build ให้สภาพแวดล้อมที่คาดการณ์ได้

#3. สร้าง Test Suite ตัวอย่าง

ไฟล์ tests/login.robot

*** Settings ***
Library    Collections

*** Test Cases ***
Login Test 01
    Log    Running Login Test 01
    Sleep    2s

Login Test 02
    Log    Running Login Test 02
    Sleep    2s

ไฟล์ tests/product.robot

*** Test Cases ***
Product Test 01
    Log    Running Product Test 01
    Sleep    2s

Product Test 02
    Log    Running Product Test 02
    Sleep    2s

ไฟล์ tests/checkout.robot

*** Test Cases ***
Checkout Test 01
    Log    Running Checkout Test 01
    Sleep    2s

Checkout Test 02
    Log    Running Checkout Test 02
    Sleep    2s

#4. สร้าง Dockerfile

FROM python:3.12-slim

WORKDIR /robot

COPY requirements.txt .

RUN pip install --no-cache-dir -r requirements.txt

COPY tests ./tests

RUN mkdir -p /robot/results

CMD ["robot", "--outputdir", "results", "tests"]

Docker Image ใช้ Python เป็น base image จากนั้นติดตั้ง Robot Framework, Pabot และ library ที่ต้องใช้

#5. Build Docker Image

docker build -t robot-tests .

ตรวจสอบ image

docker images

#6. รัน Robot Framework ใน Docker

docker run --rm robot-tests

แต่ผลลัพธ์จะอยู่ภายใน container และหายไปเมื่อ container ถูกลบ จึงควร mount directory สำหรับ report

docker run --rm \
  -v "$(pwd)/results:/robot/results" \
  robot-tests

Windows PowerShell สามารถใช้

docker run --rm `
  -v "${PWD}/results:/robot/results" `
  robot-tests

เมื่อรันเสร็จจะได้

results/
├── output.xml
├── log.html
└── report.html

#7. รัน Pabot ภายใน Docker

Pabot จะกระจายงานโดยใช้หลาย process

docker run --rm \
  -v "$(pwd)/results:/robot/results" \
  robot-tests \
  pabot --outputdir results tests

อย่างไรก็ตาม CMD ของ image เดิมจะถูกแทนที่ด้วย arguments แบบนี้ได้ไม่สะดวกในบางรูปแบบ จึงนิยมกำหนดคำสั่งเต็มผ่าน shell หรือปรับ image ให้มี ENTRYPOINT ตาม workflow ของทีม เช่น

docker run --rm \
  -v "$(pwd)/results:/robot/results" \
  robot-tests \
  sh -c "pabot --outputdir results tests"

วิธีที่ชัดเจนกว่าสำหรับ image นี้คือ override entrypoint:

docker run --rm \
  -v "$(pwd)/results:/robot/results" \
  --entrypoint pabot \
  robot-tests \
  --outputdir results tests

#8. กำหนดจำนวน Parallel Processes

ตัวอย่างใช้ 4 workers

docker run --rm \
  -v "$(pwd)/results:/robot/results" \
  --entrypoint pabot \
  robot-tests \
  --processes 4 \
  --outputdir results \
  tests

แนวคิดการทำงาน

Pabot
 ├── Process 1 -> login.robot
 ├── Process 2 -> product.robot
 ├── Process 3 -> checkout.robot
 └── Process 4 -> งานถัดไปเมื่อมี worker ว่าง

โดยปกติ Pabot แบ่งงานระดับ Test Suite ก่อน

#9. Parallel ระดับ Test Case

หากต้องการกระจายแต่ละ Test Case ใช้ --testlevelsplit

docker run --rm \
  -v "$(pwd)/results:/robot/results" \
  --entrypoint pabot \
  robot-tests \
  --processes 4 \
  --testlevelsplit \
  --outputdir results \
  tests

ตัวอย่าง

login.robot
├── Login Test 01
├── Login Test 02
├── Login Test 03
└── Login Test 04

สามารถถูกแจกไปยังหลาย worker แทนการรันทั้ง suite ใน process เดียว

ระวัง: เมื่อใช้ --testlevelsplit การออกแบบ Suite Setup/Teardown และ shared state ต้องรองรับการทำงานแบบขนาน

#10. รันเฉพาะ Tag

Robot Framework options สามารถส่งผ่าน Pabot ได้ เช่น

pabot \
  --processes 4 \
  --include smoke \
  --outputdir results \
  tests

หรือผ่าน Docker

docker run --rm \
  -v "$(pwd)/results:/robot/results" \
  --entrypoint pabot \
  robot-tests \
  --processes 4 \
  --include smoke \
  --outputdir results \
  tests

#11. ใช้ Docker Compose

ไฟล์ compose.yaml

services:
  robot:
    build: .
    volumes:
      - ./tests:/robot/tests
      - ./results:/robot/results
    entrypoint: ["pabot"]
    command:
      - "--processes"
      - "4"
      - "--outputdir"
      - "results"
      - "tests"

รันด้วย

docker compose run --rm robot

ข้อดีคือทีมไม่จำเป็นต้องจำ docker run ที่ยาว และสามารถนำ configuration เดียวกันไปประยุกต์กับ CI/CD ได้ง่าย

#12. PabotLib สำหรับ Shared Resource

Parallel testing อาจมี resource ที่ใช้พร้อมกันไม่ได้ เช่น

  • Test account
  • Database record
  • Device
  • Browser profile
  • External service ที่จำกัด concurrent session

Pabot รองรับ PabotLib สำหรับ locking และ resource distribution

pabot \
  --pabotlib \
  --processes 4 \
  --outputdir results \
  tests

ใน Robot Framework สามารถใช้ keyword ของ PabotLib เพื่อ acquire/release lock ตามการออกแบบของ test suite

#13. ข้อควรระวังของ Parallel Testing

การเพิ่มจำนวน process ไม่ได้หมายความว่าจะเร็วขึ้นแบบเส้นตรงเสมอไป เพราะยังมีข้อจำกัดจาก CPU, RAM, Browser, Database, Network และระบบที่ถูกทดสอบ

Test ที่เหมาะกับ parallel execution ควร

  • Independent ต่อกัน
  • ไม่พึ่งลำดับการทำงาน
  • ไม่ใช้ account เดียวกันโดยไม่มี locking
  • ไม่แก้ข้อมูล record เดียวกันพร้อมกัน
  • แยก test data ต่อ worker
  • cleanup ข้อมูลหลังทดสอบ
  • รองรับการรันซ้ำได้

ตัวอย่างที่ไม่ควรออกแบบ

Test A -> Create User
Test B -> Update User ที่ Test A สร้าง
Test C -> Delete User ที่ Test B แก้ไข

เพราะ Test B และ C มี dependency กับ Test A

ควรเปลี่ยนเป็น

Test A -> Setup own data -> Test -> Cleanup
Test B -> Setup own data -> Test -> Cleanup
Test C -> Setup own data -> Test -> Cleanup

#14. แนวทางเลือกจำนวน Workers

เริ่มต้นจากจำนวนที่ไม่สูง เช่น

pabot --processes 2 tests

แล้วเพิ่มเป็น

pabot --processes 4 tests

หรือ

pabot --processes 8 tests

พร้อมวัดเวลารวมและ resource utilization จริง การทดสอบ Browser UI มักใช้ RAM/CPU สูงกว่าการทดสอบ API จึงไม่ควรเลือกจำนวน worker จาก CPU core เพียงอย่างเดียว

#15. Architecture ที่แนะนำ

Developer / CI
      |
      v
+-------------------------+
| Docker Container        |
|                         |
| Robot Framework         |
|       |                 |
|       v                 |
|     Pabot               |
|   /   |   |   \         |
| W1   W2  W3   W4        |
+--|----|---|----|---------+
   |    |   |    |
   +----+---+----+
        |
        v
 Application Under Test
        |
        v
 results/
 output.xml
 log.html
 report.html

Docker แก้ปัญหาเรื่อง environment consistency ขณะที่ Pabot แก้ปัญหาเรื่อง execution time ทั้งสองจึงเหมาะสำหรับนำมาใช้ร่วมกันใน Automated Testing Pipeline

#16. คำสั่งสรุป

รันแบบปกติ:

robot --outputdir results tests

รัน Pabot:

pabot --outputdir results tests

กำหนด 4 processes:

pabot --processes 4 --outputdir results tests

Parallel ระดับ Test Case:

pabot --processes 4 --testlevelsplit --outputdir results tests

Docker + Robot Framework:

docker run --rm \
  -v "$(pwd)/results:/robot/results" \
  robot-tests

Docker + Pabot:

docker run --rm \
  -v "$(pwd)/results:/robot/results" \
  --entrypoint pabot \
  robot-tests \
  --processes 4 \
  --outputdir results \
  tests

Docker Compose:

docker compose run --rm robot

#สรุป

การนำ Robot Framework ไปรันใน Docker ทำให้ dependency และ runtime environment มีมาตรฐานเดียวกันทั้ง local development และ CI/CD ส่วน Pabot ช่วยลดเวลาของ regression suite ด้วย parallel execution

สำหรับโครงการจริง แนวทางที่เหมาะคือ Docker + pinned dependencies + Pabot + isolated test data + persistent results directory และเริ่ม parallel ที่ระดับ suite ก่อน หาก test cases มีความเป็นอิสระสูงจึงพิจารณา --testlevelsplit

#อ้างอิง