ใ€Seleniumร—Pythonใ€‘๋กœ๊ทธ์ธ ํผ ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ ํ…Œ์ŠคํŠธ 35๊ฐœ ์ž๋™ํ™” ๋ฐฉ๋ฒ•

ํ…Œ์ŠคํŠธ ์ž๋™ํ™”

๐Ÿ“Œ ์ด๋Ÿฐ ๋ถ„๊ป˜ ์ถ”์ฒœํ•ฉ๋‹ˆ๋‹ค

  • Selenium์œผ๋กœ ์›น ํผ ํ…Œ์ŠคํŠธ๋ฅผ ์ž๋™ํ™”ํ•˜๊ณ  ์‹ถ์€ ๋ถ„
  • ๋กœ๊ทธ์ธ ํผ์˜ ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ๋ฅผ ๋น ์ง์—†์ด ํ™•์ธํ•˜๊ณ  ์‹ถ์€ ๋ถ„
  • ๊ฒฝ๊ณ„๊ฐ’ยทํŠน์ˆ˜๋ฌธ์žยทSQL ์ธ์ ์…˜ ๋“ฑ์˜ ํ…Œ์ŠคํŠธ ์ผ€์ด์Šค ์„ค๊ณ„๋ฅผ ๋ฐฐ์šฐ๊ณ  ์‹ถ์€ ๋ถ„
  • Python์œผ๋กœ E2E ํ…Œ์ŠคํŠธ๋ฅผ ๊ตฌํ˜„ํ•ด๋ณด๊ณ  ์‹ถ์€ QA ์—”์ง€๋‹ˆ์–ด

โœ… ์ด ๊ธ€์„ ์ฝ์œผ๋ฉด ์•Œ ์ˆ˜ ์žˆ๋Š” ๊ฒƒ

  • Selenium์œผ๋กœ 35๊ฐœ์˜ ํผ ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ ํ…Œ์ŠคํŠธ๋ฅผ ์ž๋™ ์‹คํ–‰ํ•˜๋Š” ๋ฐฉ๋ฒ•
  • ์ „๊ฐยท๋ฐ˜๊ฐยท๊ฒฝ๊ณ„๊ฐ’ยทํŠน์ˆ˜๋ฌธ์ž ํ…Œ์ŠคํŠธ ์ผ€์ด์Šค ์„ค๊ณ„ ํŒจํ„ด
  • FAIL ์ผ€์ด์Šค์˜ ์Šคํฌ๋ฆฐ์ƒท ์ž๋™ ์ €์žฅ ๊ตฌํ˜„ ๋ฐฉ๋ฒ•
  • ํ…Œ์ŠคํŠธ ๊ฒฐ๊ณผ๋ฅผ CSVยทJSON ๋ฆฌํฌํŠธ๋กœ ์ถœ๋ ฅํ•˜๋Š” ๋ฐฉ๋ฒ•

๐Ÿ‘จโ€๐Ÿ’ป ์ž‘์„ฑ์ž ์†Œ๊ฐœ

QA ์—”์ง€๋‹ˆ์–ด๋กœ์„œ ์‹ค๋ฌด์—์„œ Selenium์„ ํ™œ์šฉํ•œ ์ž๋™ํ™” ํ…Œ์ŠคํŠธ๋ฅผ ๋‹ด๋‹นํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ๋ณธ ๊ธ€์—์„œ ์†Œ๊ฐœํ•˜๋Š” ์Šคํฌ๋ฆฝํŠธ๋Š” GitHub์— ๊ณต๊ฐœ๋˜์–ด ์žˆ์œผ๋ฉฐ, ์‹ค์ œ๋กœ ๋™์ž‘ ํ™•์ธ์ด ์™„๋ฃŒ๋œ ์ฝ”๋“œ๋ฅผ ๊ทธ๋Œ€๋กœ ํ•ด์„คํ•ฉ๋‹ˆ๋‹ค.

๋กœ๊ทธ์ธ ํผ์€ ๋Œ€๋ถ€๋ถ„์˜ ์›น ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์—์„œ ๊ฐ€์žฅ ์ค‘์š”ํ•œ ๊ธฐ๋Šฅ ์ค‘ ํ•˜๋‚˜์ž…๋‹ˆ๋‹ค. ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ๊ฐ€ ์ œ๋Œ€๋กœ ๋™์ž‘ํ•˜์ง€ ์•Š์œผ๋ฉด ์‚ฌ์šฉ์ž๊ฐ€ ๋กœ๊ทธ์ธํ•  ์ˆ˜ ์—†๋Š” ๊ฒƒ์€ ๋ฌผ๋ก , SQL ์ธ์ ์…˜์ด๋‚˜ ๋ฌด๋‹จ ์ ‘๊ทผ ๊ฐ™์€ ์‹ฌ๊ฐํ•œ ๋ณด์•ˆ ๋ฌธ์ œ๋กœ ์ด์–ด์งˆ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋ ‡๊ธฐ ๋•Œ๋ฌธ์— ๋ฆด๋ฆฌ์Šค ์ „์— ๋น ์ง์—†๋Š” ํ…Œ์ŠคํŠธ๋ฅผ ์ž๋™ํ™”ํ•ด๋‘๋Š” ๊ฒƒ์ด ๋งค์šฐ ์ค‘์š”ํ•ฉ๋‹ˆ๋‹ค.

๋กœ๊ทธ์ธ ํผ์„ ์ˆ˜๋™์œผ๋กœ ํ…Œ์ŠคํŠธํ•˜๋ฉด ์ƒ๊ฐ๋ณด๋‹ค ๊ฝค ๋ฒˆ๊ฑฐ๋กญ์ง€ ์•Š์œผ์‹ ๊ฐ€์š”? ์ „๊ฐ ๋ฌธ์žยท๋นˆ ๋ฌธ์ž์—ดยทSQL ์ธ์ ์…˜ยท์ด๋ชจ์ง€๊นŒ์ง€, ํ™•์ธํ•ด์•ผ ํ•  ํ•ญ๋ชฉ์€ ๋์ด ์—†์Šต๋‹ˆ๋‹ค. ์ด ๊ธ€์—์„œ๋Š” Selenium์„ ์‚ฌ์šฉํ•ด ๋กœ๊ทธ์ธ ํผ ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ ํ…Œ์ŠคํŠธ๋ฅผ 35๊ฐœ ์ž๋™ ์‹คํ–‰ํ•˜๋Š” Python ์Šคํฌ๋ฆฝํŠธ๋ฅผ ํ•ด์„คํ•ฉ๋‹ˆ๋‹ค. ๊ฒฐ๊ณผ๋Š” CSVยทJSON์œผ๋กœ ์ถœ๋ ฅ๋˜๊ณ , FAIL ์ผ€์ด์Šค๋Š” ์Šคํฌ๋ฆฐ์ƒท๋„ ์ž๋™ ์ €์žฅ๋ฉ๋‹ˆ๋‹ค.


  1. ํ…Œ์ŠคํŠธ ๊ด€์ 
  2. ํ…Œ์ŠคํŠธ ์ผ€์ด์Šค ์ผ๋žŒ๏ผˆ์ „์ฒด 35๊ฐœ๏ผ‰
  3. ์…‹์—… ๋ฐ ์‹คํ–‰ ๋ฐฉ๋ฒ•
    1. ํ•„์š”ํ•œ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์„ค์น˜
    2. ์‹คํ–‰ ๋ช…๋ น์–ด
  4. ์‹คํ–‰ ๊ฒฐ๊ณผ ์ƒ˜ํ”Œ
  5. ์ฝ”๋“œ ํ•ด์„ค๏ผšํ•ต์‹ฌ ํฌ์ธํŠธ 3๊ฐ€์ง€
    1. โ‘  JavaScript๋ฅผ ํ†ตํ•ด ํผ์— ๊ฐ’ ์ž…๋ ฅํ•˜๊ธฐ
    2. โ‘ก HTML5 ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ ์šฐํšŒํ•˜๊ธฐ
    3. โ‘ข FAIL ์ผ€์ด์Šค๋งŒ ์Šคํฌ๋ฆฐ์ƒท ์ €์žฅํ•˜๊ธฐ
  6. ๋ฆฌํฌํŠธ๋ฅผ CSVยทJSON์œผ๋กœ ์ž๋™ ์ถœ๋ ฅํ•˜๊ธฐ
  7. ๋” ๋ฐœ์ „์‹œํ‚ค๋Š” ์•„์ด๋””์–ด
    1. ๐Ÿ’ก ํ™œ์šฉ ์‹œ๋‚˜๋ฆฌ์˜ค ๋ฐ ํ™•์žฅ ์˜ˆ์‹œ
  8. 09. ์ž์ฃผ ๊ฒช๋Š” ๋ฌธ์ œ & ํ•ด๊ฒฐ๋ฒ•
    1. โ‘  send_keys() ๋กœ ํŠน์ˆ˜ ๋ฌธ์ž๊ฐ€ ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ์ž…๋ ฅ๋˜์ง€ ์•Š๋Š”๋‹ค
    2. โ‘ก HTML5์˜ required ์†์„ฑ์œผ๋กœ ๋ธŒ๋ผ์šฐ์ €์—์„œ ์ฐจ๋‹จ๋œ๋‹ค
    3. โ‘ข ์ „์ฒด ์Šคํฌ๋ฆฐ์ƒท์œผ๋กœ ํŒŒ์ผ ์ˆ˜๊ฐ€ ๋ฐฉ๋Œ€ํ•ด์กŒ๋‹ค
    4. โ‘ฃ ๊ธฐ๋Œ“๊ฐ’ ์„ค์ • ์‹ค์ˆ˜๋กœ FAIL์ด ๊ณ„์† ๋‚˜์™”๋‹ค
    5. โ‘ค ์˜ค๋ฅ˜ ๋ฉ”์‹œ์ง€ ์ทจ๋“ ํƒ€์ด๋ฐ์ด ๋„ˆ๋ฌด ๋นจ๋ž๋‹ค
  9. ์ •๋ฆฌ

ํ…Œ์ŠคํŠธ ๊ด€์ 

์ด๋ฒˆ ์Šคํฌ๋ฆฝํŠธ์—์„œ๋Š” ๋กœ๊ทธ์ธ ํผ์— ๋Œ€ํ•ด ์•„๋ž˜์˜ ๊ด€์ ์„ ๋น ์ง์—†์ด ํ…Œ์ŠคํŠธํ•ฉ๋‹ˆ๋‹ค. ์‹ค๋ฌด QA ํ˜„์žฅ์—์„œ๋„ ์ž์ฃผ ์‚ฌ์šฉ๋˜๋Š” ์ •์„ ๊ด€์ ๋“ค์ด๋ฏ€๋กœ, ๊ทธ๋Œ€๋กœ ์ž์‚ฌ ์ œํ’ˆ์˜ ํ…Œ์ŠคํŠธ ์„ค๊ณ„์—๋„ ์‘์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

  • ๋นˆ ์ž…๋ ฅ ์ฒดํฌ๏ผš์‚ฌ์šฉ์ž ์ด๋ฆ„ยท๋น„๋ฐ€๋ฒˆํ˜ธ๊ฐ€ ๋ฏธ์ž…๋ ฅ์ผ ๋•Œ ์˜ค๋ฅ˜๊ฐ€ ๋ฐ˜ํ™˜๋˜๋Š”๊ฐ€
  • ๋ฌธ์ž ์ข…๋ฅ˜ ์ฒดํฌ๏ผš์ „๊ฐยท์ผ๋ณธ์–ดยท์ด๋ชจ์ง€ ๋“ฑ ์˜ˆ์ƒ ์™ธ์˜ ๋ฌธ์ž ์ข…๋ฅ˜๋ฅผ ๊ฑฐ๋ถ€ํ•˜๋Š”๊ฐ€
  • ํ˜•์‹ยท๊ณต๋ฐฑ ํ˜ผ์ž… ์ฒดํฌ๏ผšํ˜•์‹์ด ์ž˜๋ชป๋œ ์ž…๋ ฅ(์ด๋ฉ”์ผ ํ˜•์‹, ๊ณต๋ฐฑ ํฌํ•จ)์„ ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ๊ฑฐ๋ถ€ํ•˜๋Š”๊ฐ€
  • ๊ฒฝ๊ณ„๊ฐ’ ์ฒดํฌ๏ผš1์žยท255์ž ๋“ฑ ๊ธธ์ด์˜ ๋์ ์—์„œ ์ด์ƒ์ด ๋ฐœ์ƒํ•˜์ง€ ์•Š๋Š”๊ฐ€
  • ๋ณด์•ˆ ์ฒดํฌ๏ผšSQL ์ธ์ ์…˜ยทXSS ๋“ฑ์˜ ๊ณต๊ฒฉ ๋ฌธ์ž์—ด์„ ๋ฌดํ•ดํ™”ํ•˜๋Š”๊ฐ€
  • ์ •์ƒ ๋กœ๊ทธ์ธ๏ผš์˜ฌ๋ฐ”๋ฅธ ์ธ์ฆ ์ •๋ณด๋กœ ๋กœ๊ทธ์ธ์— ์„ฑ๊ณตํ•˜๊ณ  ๋ฆฌ๋‹ค์ด๋ ‰ํŠธ๋˜๋Š”๊ฐ€

ํ…Œ์ŠคํŠธ ์ผ€์ด์Šค ์ผ๋žŒ๏ผˆ์ „์ฒด 35๊ฐœ๏ผ‰

ํ…Œ์ŠคํŠธ ์ผ€์ด์Šค๋Š” 4๊ฐœ์˜ ์นดํ…Œ๊ณ ๋ฆฌ๋กœ ๊ตฌ์„ฑ๋ฉ๋‹ˆ๋‹ค. ์‹ค๋ฌด์—์„œ ๋†“์น˜๊ธฐ ์‰ฌ์šด ์ „๊ฐ ๋ฌธ์ž๋‚˜ ํŠน์ˆ˜๋ฌธ์ž ๊ณ„์—ด์„ ๋‘ํ…๊ฒŒ ์ปค๋ฒ„ํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

์นดํ…Œ๊ณ ๋ฆฌ ID ๊ฑด์ˆ˜ ์ฃผ์š” ๋‚ด์šฉ
์ „๊ฐ ๋ฌธ์ž Z-01ใ€œZ-08 8๊ฑด ์ „๊ฐ ์˜์žยท์ผ๋ณธ์–ดยทํžˆ๋ผ๊ฐ€๋‚˜ยท์นดํƒ€์นด๋‚˜ยท์ „๊ฐ ๊ธฐํ˜ธยท์ „๊ฐ ๊ณต๋ฐฑ
๋ฐ˜๊ฐ ๋ฌธ์ž H-01ใ€œH-07 7๊ฑด ๋Œ€๋ฌธ์žยท์†Œ๋ฌธ์žยท์ˆซ์ž๋งŒยท๊ณต๋ฐฑ ํ˜ผ์ž…ยท์ด๋ฉ”์ผ ํ˜•์‹
๊ธธ์ด / ๊ฒฝ๊ณ„๊ฐ’ L-01ใ€œL-10 10๊ฑด ๋นˆ ๋ฌธ์ž์—ดยท1์žยท2์žยท3์žยท50์žยท255์ž
ํŠน์ˆ˜ ๋ฌธ์ž S-01ใ€œS-10 10๊ฑด SQL ์ธ์ ์…˜ยทXSSยท์ด๋ชจ์ง€ยท๊ฐœํ–‰ยทํƒญยทURL ์ธ์ฝ”๋”ฉ

โš ๏ธ ์ˆจ๊ฒจ์ง„ ์žฅ์น˜๏ผšH-01๏ผˆ์ •์ƒ ๋กœ๊ทธ์ธ๏ผ‰์€ expected_error: True๋กœ ์˜๋„์ ์œผ๋กœ ์ž˜๋ชป๋œ ๊ธฐ๋Œ“๊ฐ’์„ ์„ค์ •ํ–ˆ์Šต๋‹ˆ๋‹ค. ์ด๋Š” ๋ฐ๋ชจ์šฉ์œผ๋กœ FAIL์„ ๋ฐœ์ƒ์‹œ์ผœ ์Šคํฌ๋ฆฐ์ƒท ์ €์žฅ ๋™์ž‘์„ ํ™•์ธํ•˜๊ธฐ ์œ„ํ•œ ์žฅ์น˜์ž…๋‹ˆ๋‹ค. ์‹ค์ œ ์‚ฌ์šฉ ์‹œ์—๋Š” False๋กœ ์ˆ˜์ •ํ•˜์„ธ์š”.

์…‹์—… ๋ฐ ์‹คํ–‰ ๋ฐฉ๋ฒ•

ํ•„์š”ํ•œ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์„ค์น˜

์•„๋ž˜ ๋‘ ๊ฐ€์ง€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋งŒ ์„ค์น˜ํ•˜๋ฉด ๋™์ž‘ํ•ฉ๋‹ˆ๋‹ค. ChromeDriver ์ˆ˜๋™ ๊ด€๋ฆฌ๋Š” ํ•„์š” ์—†์Šต๋‹ˆ๋‹ค.

pip install selenium webdriver-manager

์‹คํ–‰ ๋ช…๋ น์–ด

# ๋ธŒ๋ผ์šฐ์ €๋ฅผ ํ‘œ์‹œํ•˜๋ฉฐ ์‹คํ–‰๏ผˆ๊ธฐ๋ณธ๊ฐ’๏ผ‰
python form_validation_test.py

# ํ—ค๋“œ๋ฆฌ์Šค ๋ชจ๋“œ๏ผˆ๋ธŒ๋ผ์šฐ์ € ๋น„ํ‘œ์‹œยทCI ํ™˜๊ฒฝ์šฉ๏ผ‰
python form_validation_test.py --headless

๐Ÿ’ก Tip๏ผš์ฒซ ์‹คํ–‰ ์‹œ webdriver-manager๊ฐ€ ChromeDriver๋ฅผ ์ž๋™์œผ๋กœ ๋‹ค์šด๋กœ๋“œํ•ฉ๋‹ˆ๋‹ค. ๋‘ ๋ฒˆ์งธ ์‹คํ–‰๋ถ€ํ„ฐ๋Š” ์บ์‹œ๋ฅผ ์‚ฌ์šฉํ•˜๋ฏ€๋กœ ๋น ๋ฅด๊ฒŒ ์‹œ์ž‘๋ฉ๋‹ˆ๋‹ค.

์‹คํ–‰ ๊ฒฐ๊ณผ ์ƒ˜ํ”Œ

์‹คํ–‰ํ•˜๋ฉด ํ„ฐ๋ฏธ๋„์— ์‹ค์‹œ๊ฐ„์œผ๋กœ ๊ฒฐ๊ณผ๊ฐ€ ์ถœ๋ ฅ๋ฉ๋‹ˆ๋‹ค. FAIL ์ผ€์ด์Šค๋Š” ์›์ธ๊ณผ ํ•จ๊ป˜ ์Šคํฌ๋ฆฐ์ƒท ๊ฒฝ๋กœ๋„ ํ‘œ์‹œ๋ฉ๋‹ˆ๋‹ค.

==============================================================
  Selenium Form Validation Test (headless)
  Target : //the-internet.herokuapp.com/login
  Cases  : 35
  Start  : 2025-07-01 10:00:00
==============================================================
  (01/35) Full-width alpha username      ... โœ… PASS (1823ms)
  (02/35) Full-width numeric password    ... โœ… PASS (1654ms)
  (03/35) Full-width space in username   ... โœ… PASS (1701ms)
  ...
  (09/35) Valid login (correct creds)    ... โŒ FAIL (2100ms)
       โ†’ expected_error:True / actual_error:False
       ๐Ÿ“ธ screenshots/H-01_FAIL.png
  ...
  (35/35) URL-encoded characters         ... โœ… PASS (1590ms)

โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
  Test Summary
โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
  Total  : 35
  โœ… PASS  : 34
  โŒ FAIL  : 1
  โš ๏ธ  ERROR : 0
  Rate   : 97.1%
โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€

์ฝ”๋“œ ํ•ด์„ค๏ผšํ•ต์‹ฌ ํฌ์ธํŠธ 3๊ฐ€์ง€

โ‘  JavaScript๋ฅผ ํ†ตํ•ด ํผ์— ๊ฐ’ ์ž…๋ ฅํ•˜๊ธฐ

Selenium์˜ send_keys()๋Š” ๊ฐœํ–‰๏ผˆ\n๏ผ‰์ด๋‚˜ ํƒญ๏ผˆ\t๏ผ‰๊ฐ™์€ ํŠน์ˆ˜๋ฌธ์ž๋ฅผ ์ •ํ™•ํžˆ ์ž…๋ ฅํ•˜์ง€ ๋ชปํ•˜๋Š” ๊ฒฝ์šฐ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. JavaScript๋กœ ์ง์ ‘ ๊ฐ’์„ ์„ค์ •ํ•˜๋ฉด ์–ด๋–ค ๋ฌธ์ž๋“  ์•ˆ์ „ํ•˜๊ฒŒ ์ž…๋ ฅํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

arguments[0]์—๋Š” WebElement, arguments[1]์—๋Š” ์ž…๋ ฅํ•  ๋ฌธ์ž์—ด์„ ์ „๋‹ฌํ•ฉ๋‹ˆ๋‹ค. ์ด๋ฅผ ํ†ตํ•ด ๋ธŒ๋ผ์šฐ์ €์˜ ํ‚ค ์ด๋ฒคํŠธ ์ฒ˜๋ฆฌ๋ฅผ ๊ฑด๋„ˆ๋›ฐ๊ณ  DOM ์š”์†Œ์— ์ง์ ‘ ๊ฐ’์„ ์”๋‹ˆ๋‹ค. ์ด๋ชจ์ง€ยท์ „๊ฐ ๋ฌธ์žยท์ œ์–ด ๋ฌธ์ž์ฒ˜๋Ÿผ send_keys๋กœ๋Š” ๊นจ์ง€๊ธฐ ์‰ฌ์šด ๋ฌธ์ž๋„ ํ™•์‹คํ•˜๊ฒŒ ๋™์ž‘ํ•˜๋ฏ€๋กœ, ํŠน์ˆ˜๋ฌธ์ž ๊ณ„์—ด ํ…Œ์ŠคํŠธ ์ผ€์ด์Šค๏ผˆS-05 ๊ฐœํ–‰ยทS-06 ํƒญ๏ผ‰๋Š” ์ด ๋ฐฉ์‹ ๋•๋ถ„์— ์„ฑ๋ฆฝํ•ฉ๋‹ˆ๋‹ค.

driver.execute_script("arguments[0].value = arguments[1];", u_elem, tc["username"])
driver.execute_script("arguments[0].value = arguments[1];", p_elem, tc["password"])

โ‘ก HTML5 ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ ์šฐํšŒํ•˜๊ธฐ

๋นˆ ๋ฌธ์ž์—ด ํ…Œ์ŠคํŠธ๏ผˆL-01ใ€œL-03๏ผ‰๋Š” HTML5์˜ required ์†์„ฑ ๋•Œ๋ฌธ์— ๋ธŒ๋ผ์šฐ์ € ์ธก์—์„œ ์ฐจ๋‹จ๋ฉ๋‹ˆ๋‹ค. novalidate๋ฅผ ๋ถ€์—ฌํ•˜๋ฉด ์š”์ฒญ์ด ์„œ๋ฒ„๊นŒ์ง€ ๋„๋‹ฌํ•˜๋ฏ€๋กœ ์„œ๋ฒ„ ์ธก ๋™์ž‘๊นŒ์ง€ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์œ ํšจ์„ฑ ๊ฒ€์‚ฌ ํ…Œ์ŠคํŠธ์˜ ๋ณธ๋ž˜ ๋ชฉ์ ์€ “๋ธŒ๋ผ์šฐ์ €๊ฐ€ ์˜ค๋ฅ˜๋ฅผ ํ‘œ์‹œํ•˜๋Š”๊ฐ€”๊ฐ€ ์•„๋‹ˆ๋ผ “์„œ๋ฒ„๊ฐ€ ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ์˜ค๋ฅ˜๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š”๊ฐ€”์ž…๋‹ˆ๋‹ค. ํ”„๋ก ํŠธ์—”๋“œ ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ๋ฅผ ์˜๋„์ ์œผ๋กœ ๋ฌดํšจํ™”ํ•จ์œผ๋กœ์จ ๋ฐฑ์—”๋“œ์˜ ๊ฒฌ๊ณ ์„ฑ์„ ์ง์ ‘ ํ…Œ์ŠคํŠธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

driver.execute_script(
    "document.querySelector('form').setAttribute('novalidate','true');"
)

โ‘ข FAIL ์ผ€์ด์Šค๋งŒ ์Šคํฌ๋ฆฐ์ƒท ์ €์žฅํ•˜๊ธฐ

๋ชจ๋“  ์ผ€์ด์Šค์˜ ์Šคํฌ๋ฆฐ์ƒท์„ ์ฐ์œผ๋ฉด ํŒŒ์ผ ์ˆ˜๊ฐ€ ๋ฐฉ๋Œ€ํ•ด์ง‘๋‹ˆ๋‹ค. FAIL ์‹œ์—๋งŒ ์ €์žฅํ•˜๋Š” ์„ค๊ณ„๋กœ ๋‚˜์ค‘์— ์›์ธ ํ™•์ธ์ด ํ›จ์”ฌ ์‰ฌ์›Œ์ง‘๋‹ˆ๋‹ค.

ํŒŒ์ผ๋ช…์€ {ํ…Œ์ŠคํŠธID}_FAIL.png ํ˜•์‹์ด๋ฏ€๋กœ ํŒŒ์ผ๋ช…๋งŒ ๋ด๋„ ์–ด๋А ํ…Œ์ŠคํŠธ ์ผ€์ด์Šค๊ฐ€ ์‹คํŒจํ–ˆ๋Š”์ง€ ๋ฐ”๋กœ ์•Œ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. GitHub Actions ๊ฐ™์€ CI/CD ํ™˜๊ฒฝ์—์„œ ํ…Œ์ŠคํŠธ๋ฅผ ์‹คํ–‰ํ•  ๋•Œ๋„ ์ด ์Šคํฌ๋ฆฐ์ƒท์„ ์•„ํ‹ฐํŒฉํŠธ๋กœ ์ €์žฅํ•ด๋‘๋ฉด ๋””๋ฒ„๊น… ํšจ์œจ์ด ํฌ๊ฒŒ ํ–ฅ์ƒ๋ฉ๋‹ˆ๋‹ค.

if r.status == "FAIL":
    os.makedirs("screenshots", exist_ok=True)
    ss = f"screenshots/{tc['id']}_FAIL.png"
    driver.save_screenshot(ss)
    r.screenshot = ss

๐Ÿ’ก ์‹ค๋ฌด Tip๏ผšPage Object Model๏ผˆPOM๏ผ‰์— ๋Œ€ํ•ด
์‹ค๋ฌด์—์„œ๋Š” Page Object Model๏ผˆPOM๏ผ‰์„ ์‚ฌ์šฉํ•ด ํ…Œ์ŠคํŠธ ์ฝ”๋“œ์™€ ํŽ˜์ด์ง€ ์กฐ์ž‘์„ ๋ถ„๋ฆฌํ•˜๋Š” ์„ค๊ณ„๊ฐ€ ๊ถŒ์žฅ๋ฉ๋‹ˆ๋‹ค. ์ด ์Šคํฌ๋ฆฝํŠธ๋Š” ๊ฐ„๋‹จํ•œ ๊ตฌ์„ฑ์ด์ง€๋งŒ, ํ…Œ์ŠคํŠธ ์ผ€์ด์Šค๊ฐ€ ๋Š˜์–ด๋‚˜๋ฉด LoginPage ํด๋ž˜์Šค์— ํผ ์กฐ์ž‘์„ ๋ชจ์•„๋‘๋Š” ๊ฒƒ์œผ๋กœ ์œ ์ง€๋ณด์ˆ˜์„ฑ๊ณผ ์žฌ์‚ฌ์šฉ์„ฑ์ด ํฌ๊ฒŒ ํ–ฅ์ƒ๋ฉ๋‹ˆ๋‹ค.

๋ฆฌํฌํŠธ๋ฅผ CSVยทJSON์œผ๋กœ ์ž๋™ ์ถœ๋ ฅํ•˜๊ธฐ

ํ…Œ์ŠคํŠธ ์™„๋ฃŒ ํ›„ ํƒ€์ž„์Šคํƒฌํ”„๊ฐ€ ๋ถ™์€ ๋ฆฌํฌํŠธ ํŒŒ์ผ์ด ์ž๋™์œผ๋กœ ์ƒ์„ฑ๋ฉ๋‹ˆ๋‹ค.

๐Ÿ“„ report_20250701_100000.csv
๐Ÿ“„ report_20250701_100000.json
์ถœ๋ ฅ ํ˜•์‹ ์ฃผ์š” ์šฉ๋„
CSV Excel์—์„œ ์—ด์–ด ๋ฆฌ๋ทฐยทํ•„ํ„ฐ๋งยทํŒ€ ๊ณต์œ ยท์—๋น„๋˜์Šค ์ œ์ถœ
JSON GitHub Actions ์—ฐ๋™ยทSlack ์•Œ๋ฆผยทAllure ๋ฆฌํฌํŠธ ๋ฐ์ดํ„ฐ ์—ฐ๊ณ„

๋” ๋ฐœ์ „์‹œํ‚ค๋Š” ์•„์ด๋””์–ด

โšก ๋ณ‘๋ ฌ ์‹คํ–‰์œผ๋กœ ๊ณ ์†ํ™”

concurrent.futures๋ฅผ ์‚ฌ์šฉํ•ด ๋ธŒ๋ผ์šฐ์ €๋ฅผ ์—ฌ๋Ÿฌ ๊ฐœ ๊ธฐ๋™ํ•˜๊ณ  ํ…Œ์ŠคํŠธ๋ฅผ ๋ณ‘๋ ฌ ์‹คํ–‰ํ•˜๋ฉด ์‹คํ–‰ ์‹œ๊ฐ„์„ ๋Œ€ํญ ๋‹จ์ถ•ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๐Ÿ”„ ์žฌ์‹œ๋„ ์ฒ˜๋ฆฌ ์ถ”๊ฐ€

๋„คํŠธ์›Œํฌ๊ฐ€ ๋ถˆ์•ˆ์ •ํ•œ ํ™˜๊ฒฝ์—์„œ๋„ ์•ˆ์ •์ ์œผ๋กœ ๋™์ž‘ํ•˜๋„๋ก ERROR ์ผ€์ด์Šค์— ์ž๋™ ์žฌ์‹œ๋„ ๋กœ์ง์„ ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๐Ÿ“Š ๋ฆฌํฌํŠธ ์‹œ๊ฐํ™”

JSON ๋ฆฌํฌํŠธ๋ฅผ ๋ฐ”ํƒ•์œผ๋กœ Allure๋‚˜ HTML ๋ฆฌํฌํŠธ๋ฅผ ์ƒ์„ฑํ•˜๋ฉด ํŒ€๊ณผ์˜ ๊ณต์œ ๊ฐ€ ํ›จ์”ฌ ์›ํ™œํ•ด์ง‘๋‹ˆ๋‹ค.

๐Ÿค– CI/CD ์—ฐ๋™

GitHub Actions๋‚˜ Jenkins์— ํ†ตํ•ฉํ•ด PR๋งˆ๋‹ค ์ž๋™์œผ๋กœ ํ…Œ์ŠคํŠธ๋ฅผ ์‹คํ–‰ํ•˜๋Š” ๊ตฌ์กฐ๋ฅผ ๋งŒ๋“ค ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๐Ÿ’ก ํ™œ์šฉ ์‹œ๋‚˜๋ฆฌ์˜ค ๋ฐ ํ™•์žฅ ์˜ˆ์‹œ

  • ๋งค ๋ฆด๋ฆฌ์Šค ์ „ ํšŒ๊ท€ ํ…Œ์ŠคํŠธ์˜ ์ผํ™˜์œผ๋กœ ์‹คํ–‰
  • ์‹ ๊ธฐ๋Šฅ ๋ฆด๋ฆฌ์Šค ์ „ ๋กœ๊ทธ์ธ ๊ธฐ๋Šฅ ์ •์ƒ ๋™์ž‘ ํ™•์ธ
  • ์Šคํ…Œ์ด์ง• ํ™˜๊ฒฝ์—์„œ์˜ ๋ณด์•ˆ ํ™•์ธ๏ผˆSQLiยทXSS๏ผ‰
  • ํšŒ์›๊ฐ€์ž…ยท๋น„๋ฐ€๋ฒˆํ˜ธ ๋ณ€๊ฒฝ ํผ์œผ๋กœ ์‘์šฉ ํ™•์žฅ
  • ํ…Œ์ŠคํŠธ ์ผ€์ด์Šค๋ฅผ CSV์—์„œ ์ฝ์–ด์˜ค๋Š” ๋ฐฉ์‹์œผ๋กœ ๋ณ€๊ฒฝํ•ด ๋…ธ์ฝ”๋“œ ๊ด€๋ฆฌ
  • pytest-html์ด๋‚˜ Allure์™€ ์กฐํ•ฉํ•ด ๋ฆฌํฌํŠธ ์‹œ๊ฐํ™”

09. ์ž์ฃผ ๊ฒช๋Š” ๋ฌธ์ œ & ํ•ด๊ฒฐ๋ฒ•

๊ตฌํ˜„ ์ค‘ ์‹ค์ œ๋กœ ๊ฒช์—ˆ๋˜ ๋ฌธ์ œ๋“ค์„ ์ •๋ฆฌํ–ˆ์Šต๋‹ˆ๋‹ค. ๊ฐ™์€ ๊ณณ์—์„œ ๋ง‰ํžˆ๋Š” ๋ถ„๋“ค๊ป˜ ๋„์›€์ด ๋˜๋ฉด ์ข‹๊ฒ ์Šต๋‹ˆ๋‹ค.


โ‘  send_keys() ๋กœ ํŠน์ˆ˜ ๋ฌธ์ž๊ฐ€ ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ์ž…๋ ฅ๋˜์ง€ ์•Š๋Š”๋‹ค

์ค„๋ฐ”๊ฟˆ(\n)ยทํƒญ(\t)ยท์ด๋ชจ์ง€ ๋“ฑ์˜ ํŠน์ˆ˜ ๋ฌธ์ž๋ฅผ send_keys() ๋กœ ์ž…๋ ฅํ•˜๋ฉด ๋ฌธ์ž๊ฐ€ ๊นจ์ง€๊ฑฐ๋‚˜ ์˜๋„์น˜ ์•Š์€ ๋™์ž‘์ด ๋ฐœ์ƒํ•˜๋Š” ๊ฒฝ์šฐ๊ฐ€ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค. ํŠน์ˆ˜ ๋ฌธ์ž๋Š” JavaScript๋ฅผ ํ†ตํ•ด DOM์— ์ง์ ‘ ๊ฐ’์„ ์“ฐ๋Š” ๋ฐฉ์‹์œผ๋กœ ํ•ด๊ฒฐํ–ˆ์Šต๋‹ˆ๋‹ค.

# โŒ send_keys()๋Š” ํŠน์ˆ˜ ๋ฌธ์ž๊ฐ€ ๊นจ์งˆ ์ˆ˜ ์žˆ์Œ
username_field.send_keys("test\nuser")

# โœ… JS๋ฅผ ํ†ตํ•ด ์ง์ ‘ ๊ฐ’์„ ์„ค์ •
driver.execute_script("arguments[0].value = arguments[1];", username_field, "test\nuser")

๐Ÿ’ก ํฌ์ธํŠธ๏ผš arguments[0] ์— WebElement, arguments[1] ์— ์ž…๋ ฅํ•  ๋ฌธ์ž์—ด์„ ์ „๋‹ฌํ•˜๋ฉด ๋ธŒ๋ผ์šฐ์ €์˜ ํ‚ค ์ด๋ฒคํŠธ ์ฒ˜๋ฆฌ๋ฅผ ๊ฑด๋„ˆ๋›ฐ๊ณ  ํ™•์‹คํ•˜๊ฒŒ ๊ฐ’์„ ์“ธ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.


โ‘ก HTML5์˜ required ์†์„ฑ์œผ๋กœ ๋ธŒ๋ผ์šฐ์ €์—์„œ ์ฐจ๋‹จ๋œ๋‹ค

๋นˆ ๋ฌธ์ž์—ด ํ…Œ์ŠคํŠธ๋ฅผ ์‹คํ–‰ํ•˜๋ ค ํ–ˆ๋”๋‹ˆ ํผ์˜ required ์†์„ฑ์œผ๋กœ ์ธํ•ด ๋ธŒ๋ผ์šฐ์ € ์ธก์—์„œ ์š”์ฒญ์ด ์ฐจ๋‹จ๋˜์–ด ์„œ๋ฒ„ ์ธก ๋™์ž‘์„ ํ™•์ธํ•  ์ˆ˜ ์—†์—ˆ์Šต๋‹ˆ๋‹ค.

# โŒ required๊ฐ€ ์žˆ์œผ๋ฉด ๋ธŒ๋ผ์šฐ์ €๊ฐ€ ์ฐจ๋‹จํ•˜์—ฌ ์„œ๋ฒ„์— ์ „๋‹ฌ๋˜์ง€ ์•Š์Œ
submit_button.click()

# โœ… novalidate๋ฅผ ์ถ”๊ฐ€ํ•˜์—ฌ HTML5 ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ๋ฅผ ์šฐํšŒ
driver.execute_script(
    "document.querySelector('form').setAttribute('novalidate', 'true');"
)
submit_button.click()

๐Ÿ’ก ํฌ์ธํŠธ๏ผš ใ€Œ๋ธŒ๋ผ์šฐ์ €๊ฐ€ ์˜ค๋ฅ˜๋ฅผ ํ‘œ์‹œํ•˜์ง€ ์•Š๋Š”๋‹ค๏ผํ…Œ์ŠคํŠธ ํ†ต๊ณผใ€๊ฐ€ ์•„๋‹ˆ๋ผ, ใ€Œ์„œ๋ฒ„๊ฐ€ ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ์˜ค๋ฅ˜๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š”๊ฐ€ใ€๊นŒ์ง€ ํ™•์ธํ•˜๋Š” ๊ฒƒ์ด ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ ํ…Œ์ŠคํŠธ์˜ ๋ณธ๋ž˜ ๋ชฉ์ ์ž…๋‹ˆ๋‹ค.


โ‘ข ์ „์ฒด ์Šคํฌ๋ฆฐ์ƒท์œผ๋กœ ํŒŒ์ผ ์ˆ˜๊ฐ€ ๋ฐฉ๋Œ€ํ•ด์กŒ๋‹ค

์ฒ˜์Œ์—๋Š” ์ „์ฒด 35๊ฑด์— ๋Œ€ํ•ด ๋งค๋ฒˆ ์Šคํฌ๋ฆฐ์ƒท์„ ์ฐ์—ˆ๋”๋‹ˆ ํŒŒ์ผ์ด ๋Œ€๋Ÿ‰์œผ๋กœ ์ƒ์„ฑ๋˜์–ด ์–ด๋–ค ๊ฒƒ์ด ์ค‘์š”ํ•œ์ง€ ์•Œ ์ˆ˜ ์—†๊ฒŒ ๋์Šต๋‹ˆ๋‹ค. FAIL ์ผ€์ด์Šค๋งŒ ์ €์žฅํ•˜๋Š” ์„ค๊ณ„๋กœ ๋ฐ”๊พธ๋‹ˆ ๊ด€๋ฆฌํ•˜๊ธฐ ์‰ฌ์›Œ์กŒ์Šต๋‹ˆ๋‹ค.

# โŒ ์ „์ฒด ์ €์žฅํ•˜๋ฉด ํŒŒ์ผ ์ˆ˜๊ฐ€ ๋ฐฉ๋Œ€ํ•ด์ง
driver.save_screenshot(f"screenshots/{tc['id']}.png")

# โœ… FAIL์ผ ๋•Œ๋งŒ ์ €์žฅ
if result.status == "FAIL":
    os.makedirs("screenshots", exist_ok=True)
    driver.save_screenshot(f"screenshots/{tc['id']}_FAIL.png")

๐Ÿ’ก ํฌ์ธํŠธ๏ผš ํŒŒ์ผ๋ช…์„ {ํ…Œ์ŠคํŠธID}_FAIL.png ํ˜•์‹์œผ๋กœ ํ•ด๋‘๋ฉด ์–ด๋–ค ํ…Œ์ŠคํŠธ ์ผ€์ด์Šค์—์„œ ์‹คํŒจํ–ˆ๋Š”์ง€ ํŒŒ์ผ๋ช…๋งŒ ๋ด๋„ ๋ฐ”๋กœ ์•Œ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.


โ‘ฃ ๊ธฐ๋Œ“๊ฐ’ ์„ค์ • ์‹ค์ˆ˜๋กœ FAIL์ด ๊ณ„์† ๋‚˜์™”๋‹ค

์ •์ƒ ๋กœ๊ทธ์ธ ํ…Œ์ŠคํŠธ ์ผ€์ด์Šค(H-01)์— expected_error: True ๋กœ ์ž˜๋ชป ์„ค์ •ํ•ด์„œ, ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ๋กœ๊ทธ์ธ๋˜๊ณ  ์žˆ๋Š”๋ฐ๋„ ๊ณ„์† FAIL๋กœ ํŒ์ •๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ๊ธฐ๋Œ“๊ฐ’ ์„ค์ • ์‹ค์ˆ˜๋Š” ๋””๋ฒ„๊น… ์‹œ ์•Œ์•„์ฑ„๊ธฐ ์–ด๋ ค์šฐ๋ฏ€๋กœ ์ฃผ์˜๊ฐ€ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.

# โŒ ๊ธฐ๋Œ“๊ฐ’์ด ์ž˜๋ชป๋˜๋ฉด ์ •์ƒ ๋™์ž‘์—์„œ๋„ FAIL์ด ๋จ
{"id": "H-01", "username": "tomsmith", "password": "SuperSecretPassword!", "expected_error": True}

# โœ… ์ •์ƒ ๋กœ๊ทธ์ธ์€ expected_error: False๊ฐ€ ๋งž์Œ
{"id": "H-01", "username": "tomsmith", "password": "SuperSecretPassword!", "expected_error": False}

โš ๏ธ ์ฃผ์˜๏ผš ํ…Œ์ŠคํŠธ๊ฐ€ FAILํ–ˆ์„ ๋•Œ, ๋จผ์ € ใ€Œ์ฝ”๋“œ ๋ฒ„๊ทธ์ธ์ง€ใ€ใ€Œ๊ธฐ๋Œ“๊ฐ’ ์„ค์ • ์‹ค์ˆ˜์ธ์ง€ใ€๋ฅผ ๊ตฌ๋ถ„ํ•˜๋Š” ๊ฒƒ์ด ์ค‘์š”ํ•ฉ๋‹ˆ๋‹ค.


โ‘ค ์˜ค๋ฅ˜ ๋ฉ”์‹œ์ง€ ์ทจ๋“ ํƒ€์ด๋ฐ์ด ๋„ˆ๋ฌด ๋นจ๋ž๋‹ค

ํผ ์ œ์ถœ ์งํ›„์— ์˜ค๋ฅ˜ ๋ฉ”์‹œ์ง€๋ฅผ ์ทจ๋“ํ•˜๋ ค ํ–ˆ๋”๋‹ˆ ์•„์ง ํ™”๋ฉด์ด ์—…๋ฐ์ดํŠธ๋˜์ง€ ์•Š์•„ ์˜ค๋ฅ˜ ๋ฉ”์‹œ์ง€๋ฅผ ์ฐพ์ง€ ๋ชปํ•˜๋Š” ๊ฒฝ์šฐ๊ฐ€ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค. ์ œ์ถœ ํ›„ ๋Œ€๊ธฐ ์ฒ˜๋ฆฌ๊ฐ€ ํ•„์š”ํ–ˆ์Šต๋‹ˆ๋‹ค.

# โŒ ์ œ์ถœ ์งํ›„์— ์˜ค๋ฅ˜๋ฅผ ์ทจ๋“ํ•˜๋ ค ํ•˜๋ฉด ์ฐพ์ง€ ๋ชปํ•  ์ˆ˜ ์žˆ์Œ
submit_button.click()
error = driver.find_element(By.ID, "flash")

# โœ… WebDriverWait์œผ๋กœ ์š”์†Œ๊ฐ€ ํ‘œ์‹œ๋  ๋•Œ๊นŒ์ง€ ๋Œ€๊ธฐ
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC

submit_button.click()
error = WebDriverWait(driver, 10).until(
    EC.presence_of_element_located((By.ID, "flash"))
)

๐Ÿ’ก ํฌ์ธํŠธ๏ผš time.sleep() ์œผ๋กœ ๊ณ ์ • ๋Œ€๊ธฐํ•˜๋Š” ๊ฒƒ๋ณด๋‹ค WebDriverWait ์œผ๋กœ ์กฐ๊ฑด ๋Œ€๊ธฐํ•˜๋Š” ํŽธ์ด ๋” ๋น ๋ฅด๊ณ  ์•ˆ์ •์ ์ž…๋‹ˆ๋‹ค.

์ •๋ฆฌ

์ด ๊ธ€์—์„œ๋Š” Selenium๊ณผ Python์œผ๋กœ ๋กœ๊ทธ์ธ ํผ ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ ํ…Œ์ŠคํŠธ๋ฅผ ์ž๋™ํ™”ํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์†Œ๊ฐœํ–ˆ์Šต๋‹ˆ๋‹ค.

ํฌ์ธํŠธ ๋‚ด์šฉ
ํ…Œ์ŠคํŠธ ์ผ€์ด์Šค ์ „๊ฐยท๋ฐ˜๊ฐยท๊ฒฝ๊ณ„๊ฐ’ยทํŠน์ˆ˜๋ฌธ์ž 4๊ฐ€์ง€ ์นดํ…Œ๊ณ ๋ฆฌ ์ด 35๊ฑด
์ž…๋ ฅ ๋ฐฉ๋ฒ• JS๋ฅผ ํ†ตํ•ด ์–ด๋–ค ํŠน์ˆ˜๋ฌธ์ž๋„ ํ™•์‹คํ•˜๊ณ  ์•ˆ์ „ํ•˜๊ฒŒ ์ž…๋ ฅ
์Šคํฌ๋ฆฐ์ƒท FAIL ์ผ€์ด์Šค๋งŒ ์ž๋™ ์ €์žฅ๏ผˆ๊ฑด์ˆ˜๋ฅผ ์ค„์—ฌ ๊ด€๋ฆฌ ์šฉ์ด๏ผ‰
๋ฆฌํฌํŠธ ์ถœ๋ ฅ CSVยทJSON ํ˜•์‹์œผ๋กœ ํƒ€์ž„์Šคํƒฌํ”„ ํฌํ•จ ์ž๋™ ์ƒ์„ฑ
์‹คํ–‰ ๋ชจ๋“œ --headless ์˜ต์…˜์œผ๋กœ CI/CD ํ™˜๊ฒฝ์—๋„ ๋Œ€์‘

์‹ค๋ฌด์—์„œ๋Š” ์ด๋Ÿฌํ•œ ํ…Œ์ŠคํŠธ๋ฅผ CI/CD ํŒŒ์ดํ”„๋ผ์ธ์— ํ†ตํ•ฉํ•˜๊ณ  ํ’€ ๋ฆฌํ€˜์ŠคํŠธ๋งˆ๋‹ค ์ž๋™ ์‹คํ–‰ํ•จ์œผ๋กœ์จ ํ’ˆ์งˆ์„ ์ง€์†์ ์œผ๋กœ ๊ฒ€์ฆํ•ฉ๋‹ˆ๋‹ค. Selenium ํ…Œ์ŠคํŠธ๋Š” ํšŒ๊ท€ ํ…Œ์ŠคํŠธ์—๋„ ๋„๋ฆฌ ํ™œ์šฉ๋˜๋ฉฐ, ๋ฐฐํฌ๋งˆ๋‹ค ๋กœ๊ทธ์ธ ๊ธฐ๋Šฅ์ด ์ •์ƒ์ ์œผ๋กœ ๋™์ž‘ํ•˜๋Š”์ง€ ์ž๋™์œผ๋กœ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์†Œ์Šค ์ฝ”๋“œ๋Š” GitHub์— ๊ณต๊ฐœ๋˜์–ด ์žˆ์œผ๋‹ˆ ๊ผญ ์ง์ ‘ ์‹คํ–‰ํ•ด๋ณด์„ธ์š”๏ผํผ์˜ ์ข…๋ฅ˜๋ฅผ ๋ฐ”๊พธ๋Š” ๊ฒƒ๋งŒ์œผ๋กœ ๋‹ค์–‘ํ•œ ์›น ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ํ…Œ์ŠคํŠธ์— ์‘์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ถ๊ธˆํ•œ ์ ์€ ๋Œ“๊ธ€๋กœ ๋‚จ๊ฒจ์ฃผ์„ธ์š” ๐Ÿ‘‡

ใ‚ฟใ‚คใƒˆใƒซใจURLใ‚’ใ‚ณใƒ”ใƒผใ—ใพใ—ใŸ