๐ ์ด๋ฐ ๋ถ๊ป ์ถ์ฒํฉ๋๋ค
- Selenium์ ํ์ฉํ ์น ๋ธ๋ผ์ฐ์ ์๋ํ์ ๊ด์ฌ ์๋ ๊ฐ๋ฐ์ ๋ฐ QA ์์ง๋์ด
- ํ์๊ฐ์ ยทํผ ์ ๋ ฅ ์๋ํ๋ฅผ ๋ฐฐ์ฐ๊ณ ์ถ์ ๋ถ
- ๋ก๊ทธ์ธยท๋ก๊ทธ์์ E2E ํ ์คํธ๋ฅผ ๊ตฌํํ๊ณ ์ถ์ ๋ถ
- ์คํฌ๋ฆฐ์ท ์บก์ฒ ๋ฐ ๋ก๊ทธ ๊ด๋ฆฌ๋ฅผ ์๋ํํ๊ณ ์ถ์ ๋ถ
โ ์ด ๊ธ์ ์ฝ์ผ๋ฉด ์ป์ ์ ์๋ ๊ฒ
- Selenium์ผ๋ก ์ฌ๋ฌ ํ์ด์ง์ ๊ฑธ์น ํผ ์กฐ์์ ์๋ํํ๋ ๊ตฌํ ํจํด์ ์ตํ ์ ์์ต๋๋ค
- XPath๋ฅผ ํ์ฉํ ์ ์ฐํ ์์ ํ์ ๋ฐฉ๋ฒ์ ๋ฐฐ์ธ ์ ์์ต๋๋ค
- ๋ก๊ทธ ์ถ๋ ฅยท์คํฌ๋ฆฐ์ท ๊ด๋ฆฌ์ ์ค๋ฌด์ ์ธ ๊ตฌํ ๋ฐฉ๋ฒ์ ์ต๋ํ ์ ์์ต๋๋ค
- ํ์๊ฐ์ โ ๋ก๊ทธ์์ โ ๋ก๊ทธ์ธ์ ์ ์ฒด E2E ํ๋ฆ์ ์ง์ ๊ตฌ์ฑํ ์ ์๊ฒ ๋ฉ๋๋ค
๐จโ๐ป ์ด ๊ธ์ ์ ๋ขฐ์ฑ์ ๋ํด
์ด ๊ธ์ ์ค๋ฌด์์ ์๋ํ ํ
์คํธ๋ฅผ ๋ด๋นํ๋ QA ์์ง๋์ด๊ฐ ์ค์ ๋ก ๋์์ ํ์ธํ ์ฝ๋๋ฅผ ๋ฐํ์ผ๋ก ์์ฑํ์ต๋๋ค.
์์ค์ฝ๋๋ ๋ชจ๋ GitHub์ ๊ณต๊ฐ๋์ด ์์ต๋๋ค
(automated-testing-portfolio).
์ค๋ฌด์์ ์์ ๋
ธํ์ฐ๋ฅผ ์๋์์ด ๋ด์์ต๋๋ค.
“ํ์๊ฐ์
ํผ ํ
์คํธ๋ฅผ ๋งค๋ฒ ์๋์ผ๋ก ํ๋ ๊ฑด ์ด์ ํ๊ณ์ผโฆ” ์ด๋ฐ ๊ณ ๋ฏผ์ ํด๋ณธ ์ ์์ผ์ ๊ฐ์?
์ด ๊ธ์์๋ Python ร Selenium์ ์ฌ์ฉํด ์๋๋ฐ์ ์นด๋ฉ๋ผ ํ์๊ฐ์
ํผ์
์๋์ผ๋ก ์
๋ ฅยท์ ์ถยท๋ก๊ทธ์ธ ํ์ธ๊น์ง ์ํํ๋ ์คํฌ๋ฆฝํธ๋ฅผ ์์ธํ ํด์คํฉ๋๋ค.
XPath์ ๋ณต์ ํจํด์ ํ์ฉํ ๊ฒฌ๊ณ ํ ์์ ํ์, ๋ก๊ทธ์ ์คํฌ๋ฆฐ์ท์ ํตํ ๋๋ฒ๊น
ํธ์์ฑ ๋ฑ
์ค๋ฌด์์ ๋ฐ๋ก ์ธ ์ ์๋ QA ์๋ํ ์ค๊ณ ์ฒ ํ์ ๋น ์ง์์ด ์๊ฐํฉ๋๋ค.
๐ฏ ์ด ํ ์คํธ์ ๋ชฉ์ : ์ฌ์ฉ์๊ฐ ์ ์์ ์ผ๋ก ํ์๊ฐ์ ์ ์๋ฃํ ์ ์๋์ง๋ฅผ E2E๋ก ๊ฒ์ฆํฉ๋๋ค. ๊ฐ์ ์๋ฃ๋ฟ๋ง ์๋๋ผ ์ดํ์ ๋ก๊ทธ์ธยท๋ก๊ทธ์์๊น์ง ์ผ๊ด๋๊ฒ ๋ณด์ฅํฉ๋๋ค.
- ํ ์คํธ ๊ด์
- ์ด ์คํฌ๋ฆฝํธ๋ก ํ ์ ์๋ ๊ฒ
- ์๋ํ ํ๋ก์ฐ ์ ์ฒด ๊ฐ์
- ์์ค์ฝ๋ ์ ๋ฌธ
- ์ฃผ์ ๋ฉ์๋ ํด์ค
- โ __init__() โ ํด๋์ค ์ด๊ธฐํ & ChromeDriver ์ค์
- โก log() / take_screenshot() โ ๋ก๊ทธ ๊ด๋ฆฌ์ ์๋น๋์ค ์์ง
- โข fill_basic_info() โ ์ด๋ฆยทํ๋ฆฌ๊ฐ๋ ์๋ ์ ๋ ฅ
- โฃ fill_address() โ ์ฐํธ๋ฒํธ ๊ฒ์ + ์ฃผ์ ์ ๋ ฅ
- โค fill_contact_info() โ ์ ํ๋ฒํธยท์๋ ์์ผยท์ด๋ฉ์ผ ์ ๋ ฅ
- โฅ accept_terms() โ ์ด์ฉ์ฝ๊ด ์ฒดํฌ๋ฐ์ค
- โฆ click_next_button() / click_confirm_button() โ ํ๋ฉด ์ ํ ๋ฒํผ ํด๋ฆญ
- โง login() / logout() โ ๋ก๊ทธ์ธ ํ์ธ๊ณผ ํ์ฒ๋ฆฌ
- โจ reset_password() โ ๋น๋ฐ๋ฒํธ ์ฌ์ค์ ํ๋ก์ฐ
- ์คํ ๋ก๊ทธ ์ํ
- ๋์ฑ ๋ฐ์ ์ํค๊ธฐ ์ํ ๊ฐ์ ์์ด๋์ด
- ํ์ฉ ์ฅ๋ฉดยทํ์ฅ ์
- ์ค๋ฌด ์์ฉ: POM ์ค๊ณ ร CI/CD ์ฐ๊ณ
- ์์ฃผ ๊ฒช๋ ๋ฌธ์ & ํด๊ฒฐ๋ฒ
- ์ ๋ฆฌ
ํ ์คํธ ๊ด์
์ด ์คํฌ๋ฆฝํธ๋ ๋ค์ ํ ์คํธ ๊ด์ ์ ์ปค๋ฒํฉ๋๋ค. QA ์์ง๋์ด๋ก์ “์ด ํ ์คํธ๊ฐ ๋ฌด์์ ๋ณด์ฅํ๋๊ฐ”๋ฅผ ๋ช ํํ ํ๋ ๊ฒ์ด ์ค๋ฌด์์๋ ์ค์ํฉ๋๋ค.
| ๊ด์ | ๋ด์ฉ | ์ด ์คํฌ๋ฆฝํธ์์์ ๋์ |
|---|---|---|
| โ ์ ์ ์ผ์ด์ค | ๊ฐ์ ์ฑ๊ณตยท๋ก๊ทธ์ธ ์ฑ๊ณต | ๊ฐ์ โ ๋ก๊ทธ์์ โ ๋ก๊ทธ์ธ์ ์ผ๊ด๋๊ฒ ๊ฒ์ฆ |
| โ ๏ธ ๋ฏธ์ ๋ ฅ ์ค๋ฅ | ํ์ ํญ๋ชฉ ๋ฏธ์ ๋ ฅ ์ ์ค๋ฅ ํ์ ํ์ธ | ๊ฐ ๋จ๊ณ ์คํจ ์ ๋ก๊ทธ ์ถ๋ ฅ + ์คํฌ๋ฆฐ์ท ์ ์ฅ |
| โ ๏ธ ์๋ชป๋ ์ด๋ฉ์ผ ํ์ | “@” ์์ยท๋๋ฉ์ธ ์์ ๋ฑ | ํ ์คํธ ๋ฐ์ดํฐ๋ฅผ ๊ต์ฒดํ์ฌ ๋น์ ์ ์ผ์ด์ค ๊ฒ์ฆ ๊ฐ๋ฅ |
| โ ๏ธ ๋น๋ฐ๋ฒํธ ์กฐ๊ฑด ์๋ฐ | ๋ฌธ์ ์ ๋ถ์กฑยท์ฌ์ฉ ๋ถ๊ฐ ๋ฌธ์ ๋ฑ | fill_password() ํ๋ผ๋ฏธํฐ๋ฅผ ๋ณ๊ฒฝํ์ฌ ํ์ธ ๊ฐ๋ฅ |
| ๐ ์ค๋ณต ๊ฐ์ | ๋์ผ ์ด๋ฉ์ผ๋ก 2๋ฒ์งธ ๊ฐ์ ์๋ ์์ ๋์ | ๋์ผํ email ๊ฐ์ผ๋ก ์ฌ์คํํ์ฌ ํ์ธ ๊ฐ๋ฅ |
์ด ์คํฌ๋ฆฝํธ๋ก ํ ์ ์๋ ๊ฒ
ํ๋์ ํด๋์ค๋ก ๊ฐ์ ๋ถํฐ ๋ก๊ทธ์์, ๋ก๊ทธ์ธ๊น์ง ์๊ฒฐ๋๋ ์์ ์๋ํ ํ๋ก์ฐ๋ฅผ ๊ตฌํํ๊ณ ์์ต๋๋ค.
๐
ํผ ์๋ ์ ๋ ฅ
์ด๋ฆยทํ๋ฆฌ๊ฐ๋ยท์ฃผ์ยท์ ํ๋ฒํธยท์๋ ์์ผยท์ด๋ฉ์ผ์ ์๋์ผ๋ก ์ ๋ ฅ
๐ฎ
์ฐํธ๋ฒํธ โ ์ฃผ์ ๊ฒ์
์ฐํธ๋ฒํธ ์ ๋ ฅ ํ “์ฃผ์ ๊ฒ์” ๋ฒํผ์ ํด๋ฆญํ๊ณ ํ๋ณด์์ ์ ํ
โ
์ด์ฉ์ฝ๊ด ๋์ ์ฒดํฌ๋ฐ์ค
ํด๋ฆญยท์ํ ํ์ธยทJS ํด๋ฐฑ๊น์ง ์ฒดํฌ๋ฐ์ค ์กฐ์์ ์์ ์๋ํ
๐
๋น๋ฐ๋ฒํธ ์ ๋ ฅ (ํ์ธ ํ๋ฉด)
ํ์ธ ํ๋ฉด์์ ๋น๋ฐ๋ฒํธ์ ํ์ธ์ฉ ๋น๋ฐ๋ฒํธ๋ฅผ ์๋ ์ ๋ ฅ
๐ธ
์คํฌ๋ฆฐ์ท ์๋ ์ ์ฅ
๊ฐ ๋จ๊ณ์์ ์๋์ผ๋ก PNG ์ ์ฅ. ๋๋ฒ๊น ์ ์๊ฐ์ ์ผ๋ก ํ์ธ ๊ฐ๋ฅ
๐
๋ก๊ทธ ํ์ผ ์ถ๋ ฅ
ํ์์คํฌํ๊ฐ ํฌํจ๋ ๋ก๊ทธ๋ฅผ ํ ์คํธ ํ์ผ๋ก ์ ์ฅ. ์คํ ์ด๋ ฅ์ ์ถ์ ๊ฐ๋ฅ
์๋ํ ํ๋ก์ฐ ์ ์ฒด ๊ฐ์
signup_complete() ๋ฉ์๋๊ฐ ์ ์ฒด ๋จ๊ณ๋ฅผ ํต๊ดํฉ๋๋ค. ๊ฐ ๋จ๊ณ๊ฐ ๋
๋ฆฝ๋ ๋ฉ์๋๋ก ๋ถ๋ฆฌ๋์ด ์์ด ๋๋ฒ๊น
๊ณผ ์ฌ์ฌ์ฉ์ด ์ฝ์ต๋๋ค.
| Step | ์ฒ๋ฆฌ ๋ด์ฉ | ํธ์ถ ๋ฉ์๋ | ์คํฌ๋ฆฐ์ท |
|---|---|---|---|
| 1 | ํฑ ํ์ด์ง โ ํ์๊ฐ์ ํ์ด์ง๋ก ์ด๋ | navigate_to_register_page() |
01_registration_page.png |
| 2 | ์ด๋ฆยทํ๋ฆฌ๊ฐ๋ ์ ๋ ฅ | fill_basic_info() |
โ |
| 3 | ์ฐํธ๋ฒํธยท์ฃผ์ ์ ๋ ฅ | fill_address() |
โ |
| 4 | ์ ํ๋ฒํธยท์๋ ์์ผยท์ด๋ฉ์ผ ์ ๋ ฅ | fill_contact_info() |
โ |
| 5 | ์ด์ฉ์ฝ๊ด ๋์ ์ฒดํฌ | accept_terms() |
02_form_filled.png |
| 6 | “๋ค์์ผ๋ก” ๋ฒํผ ํด๋ฆญ (์ ๋ ฅ โ ํ์ธ ํ๋ฉด) | click_next_button() |
03_confirmation_page.png |
| 7 | ํ์ธ ํ๋ฉด์์ ๋น๋ฐ๋ฒํธ ์ ๋ ฅ | fill_password() |
04_password_filled.png |
| 8 | “๊ฐ์ ํ๊ธฐ” ๋ฒํผ ํด๋ฆญ (ํ์ธ โ ์๋ฃ) | click_confirm_button() |
05_registration_complete.png |
| 9 | ๋ก๊ทธ์์ | logout() |
06_after_logout.png |
| 10 | ๊ฐ์ ๊ณ์ ์ผ๋ก ๋ก๊ทธ์ธ ํ์ธ | login() |
07_after_login.png |
| 11 | 2๋ฒ์งธ ๋ก๊ทธ์์ | logout() |
08_after_second_logout.png |
์คํฌ๋ฆฝํธ๋ฅผ ์คํํ๋ฉด ์ด๋ฆยทํ๋ฆฌ๊ฐ๋ยท์ฃผ์ยท์ ํ๋ฒํธยท์๋ ์์ผยท์ด๋ฉ์ผ์ด ๋ชจ๋ ์๋์ผ๋ก ์ ๋ ฅ๋ฉ๋๋ค. ํ ์คํธ ๋ฐ์ดํฐ๋ ๋์ ๋๋ฆฌ ํ์์ผ๋ก ๊ด๋ฆฌํ๊ธฐ ๋๋ฌธ์ ๋ค๋ฅธ ๋ฐ์ดํฐ๋ก ๊ต์ฒดํ๋ ๊ฒ๋ ๊ฐ๋จํฉ๋๋ค.
โฒ Selenium์ด ์๋ ์ ๋ ฅํ ํ์๊ฐ์ ํผ. ํ ์คํธ ๋ฐ์ดํฐ๊ฐ ์ ์ฒด ํญ๋ชฉ์ ์ ํํ๊ฒ ์ ๋ ฅ๋์ด ์์
์์ค์ฝ๋ ์ ๋ฌธ
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.ui import Select
from datetime import datetime
import os
import time
class YodobashiAutoSignup:
def __init__(self, headless=False):
self.top_url = "https://www.yodobashi.com/"
self.register_url = "https://order.yodobashi.com/yc/member/register/index.html"
options = webdriver.ChromeOptions()
options.add_argument('--disable-blink-features=AutomationControlled')
if not headless:
options.add_argument('--start-maximized')
else:
options.add_argument('--headless')
options.add_argument('--disable-popup-blocking')
self.driver = webdriver.Chrome(options=options)
self.wait = WebDriverWait(self.driver, 15)
self.log_folder = os.path.join(
os.path.expanduser("~"), "Desktop", "yodobashi_signup_logs"
)
self.setup_log_folder()
self.log_file = os.path.join(
self.log_folder,
f"signup_log_{datetime.now().strftime('%Y%m%d_%H%M%S')}.txt"
)
def setup_log_folder(self):
if not os.path.exists(self.log_folder):
os.makedirs(self.log_folder)
def log(self, message):
timestamp = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
log_message = f"[{timestamp}] {message}"
print(log_message)
with open(self.log_file, 'a', encoding='utf-8') as f:
f.write(log_message + '\n')
def take_screenshot(self, name):
screenshot_name = name.replace('(', '_').replace(')', '').replace(' ', '_')
screenshot_path = os.path.join(
self.log_folder,
f"screenshot_{screenshot_name}_{datetime.now().strftime('%H%M%S')}.png"
)
self.driver.save_screenshot(screenshot_path)
self.log(f" ๐ท Screenshot: {os.path.basename(screenshot_path)}")
return screenshot_path
# ---- ์ดํ fill_basic_info / fill_address / fill_contact_info /
# fill_password / accept_terms / click_next_button /
# click_confirm_button / navigate_to_register_page /
# signup_complete / login / logout / reset_password /
# close ๋ฑ์ ๊ตฌํ ----
# ์คํ ์์
if __name__ == "__main__":
user_data = {
"last_name": "Yamada",
"first_name": "Taro",
"last_kana": "ใคใใ",
"first_kana": "ใฟใญใฆ",
"postal_code": "1500001",
"address_detail": "1-1-1",
"building": "Sample Building 101",
"phone": "09012345678",
"birth_year": "1990",
"birth_month": "1",
"birth_day": "1",
"email": "test822211@example.com"
}
bot = YodobashiAutoSignup(headless=False)
try:
result = bot.signup_complete(user_data, password="hjerty12")
print(f"Result: {result['message']}")
finally:
bot.close()
์ฃผ์ ๋ฉ์๋ ํด์ค
์ด ํด๋์ค๋ 10๊ฐ ์ด์์ ๋ฉ์๋๋ก ๊ตฌ์ฑ๋์ด ์์ผ๋ฉฐ, ๊ฐ๊ฐ์ด ๋ ๋ฆฝ๋ ์ญํ ์ ๋ด๋นํฉ๋๋ค. ์ด๋ฅผ ํตํด ๊ฐ๋ณ ๋๋ฒ๊น ยท์ฌ์ฌ์ฉยทํ์ฅ์ด ์ฌ์ด ์ค๊ณ๋ฅผ ์คํํ๊ณ ์์ต๋๋ค.
โ __init__() โ ํด๋์ค ์ด๊ธฐํ & ChromeDriver ์ค์
ํด๋์ค ์ธ์คํด์ค ์์ฑ ์ ํธ์ถ๋๋ ์ด๊ธฐํ ๋ฉ์๋์
๋๋ค. ์ธ์ headless=False๋ฅผ True๋ก ๋ณ๊ฒฝํ๋ ๊ฒ๋ง์ผ๋ก ๋ธ๋ผ์ฐ์ ๋ฅผ ์จ๊ธฐ๊ณ ์คํํ ์ ์์ด CI/CD ํ๊ฒฝ์์์ ์คํ์๋ ๋์ํ๊ณ ์์ต๋๋ค.
๐ ํฌ์ธํธ: --disable-blink-features=AutomationControlled ์ต์
์ผ๋ก Selenium์ ์๋ ์กฐ์์ ๊ฐ์งํ๊ธฐ ์ด๋ ต๊ฒ ๋ง๋ญ๋๋ค.
โ ์ฃผ์: ๋ก๊ทธ ํ์ผ๊ณผ ์คํฌ๋ฆฐ์ท์ ๋ฐ์คํฌํฑ์ yodobashi_signup_logs ํด๋์ ์๋ ์ ์ฅ๋ฉ๋๋ค. ์คํํ ๋๋ง๋ค ํ์์คํฌํ๊ฐ ํฌํจ๋ ์ ํ์ผ์ด ์์ฑ๋๋ฏ๋ก ์คํ ์ด๋ ฅ์ด ๋ฎ์ด์ฐ์ฌ์ง์ง ์์ต๋๋ค.
โก log() / take_screenshot() โ ๋ก๊ทธ ๊ด๋ฆฌ์ ์๋น๋์ค ์์ง
log()๋ ํ์์คํฌํ๊ฐ ํฌํจ๋ ๋ฉ์์ง๋ฅผ ์ฝ์๊ณผ ํ
์คํธ ํ์ผ ์์ชฝ์ ๋์ ์ถ๋ ฅํฉ๋๋ค. take_screenshot()์ ์์์ ํ์ด๋ฐ์ ํ๋ฉด์ PNG๋ก ์ ์ฅํฉ๋๋ค. ์ด ๋ ๋ฉ์๋๊ฐ ๋ชจ๋ ๋จ๊ณ์ ์ฝ์
๋์ด ์์ด, ํ
์คํธ ์คํจ ์ ์ด๋ค ๋จ๊ณ์์ ๋ฌด์จ ์ผ์ด ์ผ์ด๋ฌ๋์ง ์ถ์ ํ ์ ์์ต๋๋ค.
๐ก ์ค๋ฌด Tip: QA ํ์ฅ์์๋ “ํ ์คํธ ์๋น๋์ค(์ฆ์ )”์ ์ ์ถ์ด ์๊ตฌ๋๋ ๊ฒฝ์ฐ๊ฐ ๋ง์ต๋๋ค. ์คํฌ๋ฆฐ์ท์ ์๋ ์์งํด ๋๋ฉด ํ ์คํธ ๋ณด๊ณ ์ ์์ฑ ๊ณต์๋ฅผ ๋ํญ ์ ๊ฐํ ์ ์์ต๋๋ค.
โข fill_basic_info() โ ์ด๋ฆยทํ๋ฆฌ๊ฐ๋ ์๋ ์ ๋ ฅ
๋ชจ๋ input[type="text"]๋ฅผ ์ผ๊ด ์ทจ๋ํ์ฌ placeholder ์์ฑ๊ณผ name ์์ฑ์ ๋ฌธ์์ด๋ก ํ๋๋ฅผ ํน์ ํฉ๋๋ค. ์์ฑ๊ฐ์ผ๋ก ํ๋จํ๋ ์ ๊ทผ์ ์ทจํจ์ผ๋ก์จ ํผ์ ์์๊ฐ ๋ฐ๋์ด๋ ๊นจ์ง์ง ์๊ฒ ๋์ด ์์ต๋๋ค.
โ ํฌ์ธํธ: 'kana' not in name_attr.lower() ์กฐ๊ฑด์ผ๋ก ๊ฐ๋ ๊ณ์ด ํ๋๋ฅผ ๋ช
์์ ์ผ๋ก ์ ์ธํฉ๋๋ค.
โฃ fill_address() โ ์ฐํธ๋ฒํธ ๊ฒ์ + ์ฃผ์ ์ ๋ ฅ
์ฃผ์ ์ ๋ ฅ์ ์ฐํธ๋ฒํธ ๊ฒ์ โ ํ๋ณด ์ ํ โ ๋ฒ์ง ์ ๋ ฅ์ด๋ผ๋ ๋ณต์ ๋จ๊ณ๊ฐ ์ฝํ ์ฒ๋ฆฌ์ ๋๋ค. 7์๋ฆฌ ์ฐํธ๋ฒํธ๋ฅผ ์ 3์๋ฆฌยท๋ค 4์๋ฆฌ๋ก ๋ถํ ํ์ฌ ์ ๋ ฅํฉ๋๋ค.
postal = user_data['postal_code'] # ์: '1500001'
postal1 = postal[:3] # '150'
postal2 = postal[3:] # '0001'
# name ์์ฑ์ 'zip' ๋๋ 'postal'์ ํฌํจํ๋ input์ ์ถ์ถ
postal_inputs = []
for inp in self.driver.find_elements(By.XPATH, "//input[@type='text']"):
name_attr = inp.get_attribute('name') or ''
if 'zip' in name_attr.lower() or 'postal' in name_attr.lower():
postal_inputs.append(inp)
๐ ์ค๊ณ ํฌ์ธํธ: ์์ ์ผ์น๋ณด๋ค ๋ถ๋ถ ์ผ์น๊ฐ ๋ณ๊ฒฝ์ ๊ฐํ๋ค๋ ์ค๋ฌด์ ์ธ ์ฌ๊ณ ๋ฐฉ์์ ๋๋ค.
โค fill_contact_info() โ ์ ํ๋ฒํธยท์๋ ์์ผยท์ด๋ฉ์ผ ์ ๋ ฅ
์ ํ๋ฒํธ๋ 11์๋ฆฌ์ 10์๋ฆฌ ์์ชฝ ํจํด์ ๋์ํ์ฌ 3๋ถํ ๋ก ์
๋ ฅํฉ๋๋ค. ์๋
์์ผ์ “์”๊ณผ “์ผ”์ <select> ํ๊ทธ ๋๋กญ๋ค์ด์ผ๋ก, Select ํด๋์ค๋ฅผ ์ฌ์ฉํ์ฌ select_by_value()๋ก ์ ํํฉ๋๋ค.
๐ก Tip: ๋๋กญ๋ค์ด ์กฐ์์๋ ๋ฐ๋์ Select(element)๋ก ๋ํํด์ผ ํฉ๋๋ค. ์ง์ click()ํด๋ ์ต์
์ด ์ ํ๋์ง ์์ผ๋ฏ๋ก ์ฃผ์ํ์ธ์.
โฅ accept_terms() โ ์ด์ฉ์ฝ๊ด ์ฒดํฌ๋ฐ์ค
์ผ๋ฐ ํด๋ฆญ โ JS ํด๋ฆญ โ JS๋ก ์ง์ ํ๋กํผํฐ ๋ณ๊ฒฝ์ 3๋จ๊ณ ํด๋ฐฑ์ผ๋ก ํ์คํ๊ฒ ์ฒดํฌ๋ฅผ ๋ฃ์ต๋๋ค. ํด๋ฆญ ํ์ is_selected()๋ก ์ํ๋ฅผ ์ฌํ์ธํ๋ ๊ฒ์ด ๊ฒฌ๊ณ ํจ์ ํฌ์ธํธ์
๋๋ค.
๐ก Tip: arguments[0].click()๊ณผ arguments[0].checked = true๋ ๋ณ๊ฐ์ด๋ฏ๋ก ๋ ๋ค ์ค๋นํด ๋๋ฉด ๊ฑฐ์ ๋ชจ๋ ์ผ์ด์ค์ ๋์ ๊ฐ๋ฅํฉ๋๋ค.
โฆ click_next_button() / click_confirm_button() โ ํ๋ฉด ์ ํ ๋ฒํผ ํด๋ฆญ
๋ฒํผ ํ ์คํธ๊ฐ ๋ณต์ ํจํด์ผ๋ก ์์๋๊ธฐ ๋๋ฌธ์ XPath ์ ๋ ํฐ๋ฅผ ๋ฐฐ์ด๋ก ๊ฐ์ง๊ณ ์์์๋ถํฐ ์์๋๋ก ์๋ํ๋ ๋ฐฉ์์ ์ฑ์ฉํ๊ณ ์์ต๋๋ค.
โ ์ค๊ณ ํฌ์ธํธ: ๋ณต์์ ์ ๋ ํฐ๋ฅผ ์ฐ์ ์์๋ฅผ ๋ถ์ฌ ์๋ํ๋ ํด๋ฐฑ ์ค๊ณ๋ ์ค๋ฌด Selenium ํ ์คํธ์์ ๊ผญ ๋์ ํ๊ณ ์ถ์ ์๋ฒ์ ๋๋ค.
โง login() / logout() โ ๋ก๊ทธ์ธ ํ์ธ๊ณผ ํ์ฒ๋ฆฌ
๊ฐ์ ์๋ฃ ํ ๋ฐ๋ก ๋ก๊ทธ์์ โ ๋ก๊ทธ์ธ์ ์คํํจ์ผ๋ก์จ ๊ฐ์ ์๋ฃ๋ฟ๋ง ์๋๋ผ ๋ก๊ทธ์ธ ๊ฐ๋ฅ ์ํ๊น์ง ์ผ๊ด๋๊ฒ ํ์ธํ ์ ์์ต๋๋ค.
| ๋ฉ์๋ | ์์ ํ์์ ๊ถ๋ฆฌ | ์ฑ๊ณต ํ์ ๋ก์ง |
|---|---|---|
login() |
๋ณต์ ์ ๋ ํฐ๋ฅผ ์์๋๋ก ์๋. logout ํฌํจ href๋ ์ ์ธ | body ๋ด์ ์ธ์ฌ๋ง์ด ํฌํจ๋๋์ง ํ์ธ |
logout() |
์ฌ์ฉ์ ์ด๋ฆ ๋งํฌ ํด๋ฆญ์ผ๋ก ๋๋กญ๋ค์ด์ ์ด๊ณ “๋ก๊ทธ์์” ์์๋ฅผ ๊ฒ์ | ๋ก๊ทธ์์ ์์๋ฅผ ์ฐพ์ง ๋ชปํ๋ฉด “์ด๋ฏธ ๋ก๊ทธ์์ ์ํ”๋ก์ True ๋ฐํ |
โจ reset_password() โ ๋น๋ฐ๋ฒํธ ์ฌ์ค์ ํ๋ก์ฐ
“๋น๋ฐ๋ฒํธ๋ฅผ ์์ผ์ ๋ถ” ๋งํฌ๋ถํฐ ์์๋๋ ๋น๋ฐ๋ฒํธ ์ฌ์ค์ ํ๋ก์ฐ๋ฅผ ์๋ํํฉ๋๋ค. ์ด ๋ฉ์๋๋ฅผ ์ฌ์ฉํจ์ผ๋ก์จ ๋น๋ฐ๋ฒํธ ์ฌ์ค์ ๊ธฐ๋ฅ์ ๋์ ํ์ธ ํ ์คํธ๋ ์๋ํํ ์ ์์ต๋๋ค.
๐ ํฌ์ธํธ: ์ด์ ๋จ๊ณ์ ์ํ์ ์์กดํ์ง ์๋ ๊ฒฌ๊ณ ํ ํ ์คํธ ํ๋ก์ฐ๋ฅผ ์คํํ๊ณ ์์ต๋๋ค.
์คํ ๋ก๊ทธ ์ํ
์คํํ๋ฉด ์ฝ์๊ณผ ํ ์คํธ ํ์ผ์ ๋ค์๊ณผ ๊ฐ์ ๋ก๊ทธ๊ฐ ์ถ๋ ฅ๋ฉ๋๋ค. ๊ฐ ๋จ๊ณ์ ์คํ ์ํฉ์ ์ค์๊ฐ์ผ๋ก ํ์ธํ ์ ์์ต๋๋ค.
[2025-07-10 14:32:01] ======================================================================
[2025-07-10 14:32:01] Yodobashi Camera Member Registration Automation (Full Flow)
[2025-07-10 14:32:02] [Step 1] Navigating to member registration page...
[2025-07-10 14:32:05] โ Registration link clicked
[2025-07-10 14:32:08] [Step 2] Filling in basic information...
[2025-07-10 14:32:09] โ Last name: Yamada
[2025-07-10 14:32:09] โ First name: Taro
[2025-07-10 14:32:11] [Step 3] Filling in address information...
[2025-07-10 14:32:12] โ Postal code: 150-0001
[2025-07-10 14:32:14] โ Address search executed
[2025-07-10 14:32:18] ๐ท Screenshot: screenshot_02_form_filled_143218.png
[2025-07-10 14:32:32] โ Member registration complete!
[2025-07-10 14:32:45] โ Login successful!
[2025-07-10 14:32:50] Final result: Registration, logout, login, and logout all completed!
โ ๏ธ ์ด๋ฐ ์๋ฌ๊ฐ ๋์ค๋ ๊ฒฝ์ฐ๋๏ผ
======================================================================
๊ฒฐ๊ณผ: ๋น๋ฐ๋ฒํธ ์
๋ ฅ์ ์คํจํ์ต๋๋ค
Email: test****@example.com
Password: ******
๋ก๊ทธ ํ์ผ: C:\Users\HP\Desktop\yodobashi_signup_logs\signup_log_****.txt
======================================================================
์ด ์๋ฌ๊ฐ ๋์ค๋ ๊ฐ์ฅ ํํ ์์ธ์ ์ด๋ฏธ ๋ฑ๋ก๋ ์ด๋ฉ์ผ ์ฃผ์๋ฅผ ์ฌ์ฉํ๊ณ ์๋ ๊ฒฝ์ฐ์ ๋๋ค.
email๊ฐ์ ๋ค๋ฅธ ์ฃผ์(์:test_99999@example.com)๋ก ๋ณ๊ฒฝํ์ฌ ์ฌ์คํํ์ธ์- ํ ์คํธ์ฉ์ผ๋ก ์ฌ๋ฌ ๊ฐ์ ์ด๋ฉ์ผ ์ฃผ์ ํจํด์ ๋ฏธ๋ฆฌ ์ค๋นํด ๋๋ฉด ํธ๋ฆฌํฉ๋๋ค
- ๋์ผํ ์ฃผ์๋ก ์ฌ๊ฐ์ ์ ์๋ํ๋ฉด “์ค๋ณต ๊ฐ์ ์๋ฌ”๊ฐ ๋ฐ์ํ์ฌ ๋น๋ฐ๋ฒํธ ์ ๋ ฅ ๋จ๊ณ๊น์ง ์งํํ ์ ์์ต๋๋ค
ํ์์ ํ๊ฒฝ์์ ์ค์ ๋ก ์คํํ์ ๋์ ํฐ๋ฏธ๋ ์ถ๋ ฅ์ ๋๋ค. ๋จ๊ณ 1~3์ด ์์๋๋ก ์คํ๋์ด ๊ฐ ์ ๋ ฅ ํญ๋ชฉ์ด โ๋ก ํ์ธ๋๊ณ ์๋ ๊ฒ์ ์ ์ ์์ต๋๋ค.
โฒ ์ค์ ํฐ๋ฏธ๋ ์ถ๋ ฅ. ๋จ๊ณ1๏ผํ์ด์ง ์ด๋๏ผโ ๋จ๊ณ2๏ผ๊ธฐ๋ณธ ์ ๋ณด ์ ๋ ฅ๏ผโ ๋จ๊ณ3๏ผ์ฃผ์ ์ ๋ ฅ๏ผ์ด ์์๋๋ก ์คํ๋จ
๋์ฑ ๋ฐ์ ์ํค๊ธฐ ์ํ ๊ฐ์ ์์ด๋์ด
๐ ๋ฐ์ดํฐ ๊ธฐ๋ฐ ํ ์คํธ (DDT)
user_data๋ฅผ CSV๋ Excel์์ ์ฝ์ด์ค๋ ํ์์ผ๋ก ํ๋ฉด ๋ณต์์ ์ฌ์ฉ์๋ก ์ผ๊ด ํ
์คํธ๊ฐ ๊ฐ๋ฅํฉ๋๋ค.
โก ๋ณ๋ ฌ ์คํ์ผ๋ก ๊ณ ์ํ
concurrent.futures.ThreadPoolExecutor๋ pytest-xdist๋ฅผ ์ฌ์ฉํ ๋ณ๋ ฌ ์คํ์ผ๋ก ๋ณต์ ๊ณ์ ์ ๊ฐ์
ํ์ธ์ ๋์์ ์ํํ ์ ์์ต๋๋ค.
๐ก๏ธ ์ฌ์๋ ๊ธฐ๋ฅ ๊ฐํ
๋คํธ์ํฌ ์ง์ฐ ๋์ฑ
์ผ๋ก tenacity ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ฌ์ฉํ ์๋ ์ฌ์๋ ๊ธฐ๊ตฌ๋ฅผ ์ถ๊ฐํ๋ฉด ๋์ฑ ๊ฒฌ๊ณ ํด์ง๋๋ค.
๐ HTML ๋ฆฌํฌํธ ์ถ๋ ฅ
pytest + allure-pytest๋ฅผ ์กฐํฉํ์ฌ ์คํฌ๋ฆฐ์ท์ด ํฌํจ๋ HTML ํ
์คํธ ๋ฆฌํฌํธ๋ฅผ ์๋ ์์ฑํ ์ ์์ต๋๋ค.
ํ์ฉ ์ฅ๋ฉดยทํ์ฅ ์
๐ ์ด ์ฝ๋๊ฐ ๋น๋๋ ์ฅ๋ฉด
๐งช ๋ฆฌ๊ทธ๋ ์ ํ ์คํธ
๋ฆด๋ฆฌ์ค ์ ์ ํ์๊ฐ์ ํ๋ก์ฐ๊ฐ ๋ง๊ฐ์ง์ง ์์๋์ง ์๋์ผ๋ก ํ์ธํฉ๋๋ค. CI/CD์ ํตํฉํ๋ฉด ๋งค ๋ฐฐํฌ ํ์ ์๋ ์คํํ ์ ์์ต๋๋ค.
๐ ์ธ์ ํ ์คํธ ์๋ํ
์ดํด๊ด๊ณ์ ๋ณด๊ณ ์ฉ์ผ๋ก ์คํฌ๋ฆฐ์ท์ด ํฌํจ๋ ์๋น๋์ค๋ฅผ ์๋ ์์งํฉ๋๋ค. ํ ์คํธ ์๋น๋์ค ์์ฑ ๊ณต์๋ฅผ ๋ํญ ์ญ๊ฐํ ์ ์์ต๋๋ค.
๐ง E2E ํ ์คํธ ํ์ต ๊ต์ฌ
Selenium์ ์์ ํ์ยท๋๊ธฐ ์ฒ๋ฆฌยท์คํฌ๋ฆฐ์ทยท๋ก๊ทธ ์ถ๋ ฅ ๋ฑ ์ค๋ฌด์ ์ธ ํจํด์ด ํ๋ฐ ๋ชจ์ธ ํ์ต ๊ต์ฌ๋ก์ ์ต์ ์ ๋๋ค.
๐ ๋น๋ฐ๋ฒํธ ์ฌ์ค์ ํ๋ก์ฐ ํ์ธ
reset_password() ๋ฉ์๋๋ก “๋น๋ฐ๋ฒํธ๋ฅผ ์์ผ์ ๋ถ” ํ๋ก์ฐ์ ๋์ ํ์ธ๋ ์๋ํํฉ๋๋ค.
์ค๋ฌด ์์ฉ: POM ์ค๊ณ ร CI/CD ์ฐ๊ณ
๐ Page Object Model (POM)
ํ์ด์ง๋ณ๋ก ํด๋์ค๋ฅผ ๋๋๊ณ ์กฐ์ ๋ก์ง๊ณผ ํ ์คํธ ๋ก์ง์ ๋ถ๋ฆฌํ๋ ๊ฒ์ด Selenium์ ์ ์ ์ค๊ณ์ ๋๋ค.
pages/register_page.py โ ์กฐ์ ๋ก์ง
tests/test_register.py โ ํ
์คํธ ์ผ์ด์คโ๏ธ CI/CD ํตํฉ
GitHub Actions์ ์กฐํฉํ๋ฉด ๋ฐฐํฌํ ๋๋ง๋ค ํ์๊ฐ์ ํ๋ก์ฐ์ ํ์ง์ ์๋์ผ๋ก ๋ณด์ฅํ ์ ์์ต๋๋ค.
push โ GitHub Actions ์คํ
โ pytest ์คํ โ ๋ฆฌํฌํธ ์์ฑ์์ฃผ ๊ฒช๋ ๋ฌธ์ & ํด๊ฒฐ๋ฒ
๊ตฌํ ์ค ์ค์ ๋ก ๊ฒช์๋ ๋ฌธ์ ๋ค์ ์ ๋ฆฌํ์ต๋๋ค. ๊ฐ์ ๊ณณ์์ ๋งํ๋ ๋ถ๋ค๊ป ๋์์ด ๋๋ฉด ์ข๊ฒ ์ต๋๋ค.
โ ์ฒดํฌ๋ฐ์ค๊ฐ ์ผ๋ฐ ํด๋ฆญ์ผ๋ก ๋ฐ์ํ์ง ์๋๋ค
์ด์ฉ์ฝ๊ด ์ฒดํฌ๋ฐ์ค์ click() ์ ์คํํด๋ ์ฒดํฌ๊ฐ ๋์ง ์๋ ๊ฒฝ์ฐ๊ฐ ๋ฐ์ํ์ต๋๋ค. ์์ธ์ ์ฒดํฌ๋ฐ์ค ๋ณธ์ฒด๊ฐ visibility:hidden ์ผ๋ก ์จ๊ฒจ์ ธ ์๊ณ , ์ค์ ๋ก๋ ๋ผ๋ฒจ ์์๋ฅผ ํด๋ฆญํ๋๋ก ๊ตฌํ๋์ด ์์๊ธฐ ๋๋ฌธ์
๋๋ค.
# โ ์ผ๋ฐ ํด๋ฆญ์ผ๋ก๋ ๋ฐ์ํ์ง ์์ ์ ์์
checkbox = driver.find_element(By.ID, "js_i_checkPrivacyPolicyAgreement")
checkbox.click()
# โ
JS ํด๋ฆญ โ ํ๋กํผํฐ ์ง์ ๋ณ๊ฒฝ์ 3๋จ๊ณ ํด๋ฐฑ์ผ๋ก ํด๊ฒฐ
try:
checkbox.click()
except:
driver.execute_script("arguments[0].click();", checkbox)
if not checkbox.is_selected():
driver.execute_script("arguments[0].checked = true;", checkbox)
๐ก ํฌ์ธํธ๏ผ arguments[0].click()๏ผํด๋ฆญ ์ด๋ฒคํธ ๋ฐํ๏ผ๊ณผ arguments[0].checked = true๏ผํ๋กํผํฐ ์ง์ ๋ณ๊ฒฝ๏ผ๋ ๋ค๋ฆ
๋๋ค. ๋ ๋ค ๊ฐ๊ณ ์์ผ๋ฉด ๊ฑฐ์ ๋ชจ๋ ๊ฒฝ์ฐ์ ๋์ํ ์ ์์ต๋๋ค.
โก ๋๋กญ๋ค์ด๏ผselect ํ๊ทธ๏ผ์ ์ง์ ํด๋ฆญ์ผ๋ก ์ ํํ ์ ์๋ค
์๋
์์ผ์ ใ์ใใ์ผใ์ด ๋๋กญ๋ค์ด์ผ๋ก ๋์ด ์์ด์ ์ผ๋ฐ click() ์ผ๋ก๋ ์ ํํ ์ ์์์ต๋๋ค. Select ํด๋์ค๋ฅผ ์ฌ์ฉํ์ง ์์ผ๋ฉด ๊ฐ์ ์ ํํ ์ ์๋ค๋ ๊ฒ์ ๋ชฐ๋ผ์ ํค๋งธ์ต๋๋ค.
# โ ์ง์ ํด๋ฆญ์ผ๋ก๋ ์ ํํ ์ ์์
month_element.click()
# โ
Select ํด๋์ค๋ก ๊ฐ์ธ์ ์กฐ์
from selenium.webdriver.support.ui import Select
select = Select(month_element)
select.select_by_value("1") # 1์ ์ ํ
๐ก ํฌ์ธํธ๏ผ <select> ํ๊ทธ ์กฐ์์๋ ๋ฐ๋์ Select ํด๋์ค๋ฅผ ์ฌ์ฉํฉ๋๋ค. ์ํฌํธ๋ฅผ ์์ง ์๋๋ก ์ฃผ์ํ์ธ์.
โข ๋ฒํผ์ XPath๊ฐ 1ํจํด์ด๋ฉด ์ฝ๊ฒ ๋ง๊ฐ์ง๋ค
ใ๋ค์์ผ๋ก ์งํใ ๋ฒํผ์ XPath 1ํจํด์ผ๋ก ์ง์ ํ๋๋ ์ฌ์ดํธ์ ๋ฏธ์ธํ ๋ณ๊ฒฝ์ผ๋ก ๋ฒํผ์ ์ฐพ์ง ๋ชปํ๊ฒ ๋์ต๋๋ค. ๋ฒํผ ํ ์คํธ๋ ใ๋ค์ใใ๋ค์์ผ๋กใใ์งํใ ๋ฑ ์ฌ๋ฌ ํจํด์ด ์กด์ฌํ๋ ๊ฒฝ์ฐ๊ฐ ๋ง์ ํ๋๋ง์ผ๋ก๋ ๋ถ์กฑํ์ต๋๋ค.
# โ 1ํจํด๋ง์ผ๋ก๋ ์ฝ๊ฒ ๋ง๊ฐ์ง
button = driver.find_element(By.XPATH, "//button[text()='๋ค์์ผ๋ก ์งํ']")
# โ
์ฌ๋ฌ ํจํด์ ์์๋๋ก ์๋ํ๋ ํด๋ฐฑ ์ค๊ณ
selectors = [
"//button[contains(text(),'๋ค์')]",
"//input[@type='submit']",
"//a[contains(text(),'๋ค์')]",
]
for selector in selectors:
elements = driver.find_elements(By.XPATH, selector)
if elements:
elements[0].click()
break
๐ก ํฌ์ธํธ๏ผ ์ฌ๋ฌ ์ ๋ ํฐ๋ฅผ ์ฐ์ ์์๋ฅผ ์ ํด ์์๋๋ก ์๋ํ๋ ํด๋ฐฑ ์ค๊ณ๋ ์ค๋ฌด Selenium ํ ์คํธ์์ ๊ผญ ๋์ ํ๊ณ ์ถ์ ๊ธฐ๋ฒ์ ๋๋ค.
โฃ ์ฐํธ๋ฒํธ ํ๋ ํน์ ์ ์ ๋ฅผ ๋จน์๋ค
์ฐํธ๋ฒํธ ํ๋๋ฅผ id ๋ก ์ง์ ์ง์ ํ๋๋ ์ฌ์ดํธ ๋ฆฌ๋ด์ผ๋ก id ๊ฐ ๋ฐ๋์ด ํ
์คํธ๊ฐ ๋ง๊ฐ์ก์ต๋๋ค. ์์ ์ผ์น๋ณด๋ค ๋ถ๋ถ ์ผ์น๊ฐ ๋ณ๊ฒฝ์ ๋ ๊ฐํ๋ค๋ ๊ฒ์ ๋ฐฐ์ ์ต๋๋ค.
# โ id์ ์์ ์ผ์น๋ ๋ณ๊ฒฝ์ ์ทจ์ฝ
driver.find_element(By.ID, "zipCode1")
# โ
name ์์ฑ์ ๋ถ๋ถ ์ผ์น๋ก ์ ์ฐํ๊ฒ ๋์
for inp in driver.find_elements(By.XPATH, "//input[@type='text']"):
name_attr = inp.get_attribute('name') or ''
if 'zip' in name_attr.lower() or 'postal' in name_attr.lower():
postal_inputs.append(inp)
๐ก ํฌ์ธํธ๏ผ ID๋ ํด๋์ค๋ช ์ ์์ ์ผ์น๋ณด๋ค ์์ฑ๊ฐ์ ๋ถ๋ถ ์ผ์น๋ก ์ฐพ๋ ํธ์ด ์ฌ์ดํธ ๋ณ๊ฒฝ์ ๊ฐํ๊ณ ์ ์ง๋ณด์ ๋น์ฉ์ด ์ค์ด๋ญ๋๋ค.
โค ๋ก๊ทธ์ธ ์ฑ๊ณต ์ฌ๋ถ ํ์ ์ด ์ด๋ ค์ ๋ค
๋ก๊ทธ์ธ ํ ใ์ฑ๊ณตํ๋์ง ์ฌ๋ถใ๋ฅผ ํ์ ํ๋ ๋ฐฉ๋ฒ์ผ๋ก ๊ณ ๋ฏผํ์ต๋๋ค. URL์ด ๋ฐ๋์ง ์๋ ๊ฒฝ์ฐ๋ ์์ด, ํ์ด์ง ํ์ดํ์ด๋ URL๋ง์ผ๋ก๋ ํ์ ํ ์ ์๋ ์ํฉ์ด ์์์ต๋๋ค.
# โ URL๋ง์ผ๋ก๋ ํ์ ํ ์ ์๋ ๊ฒฝ์ฐ๊ฐ ์์
if "mypage" in driver.current_url:
print("๋ก๊ทธ์ธ ์ฑ๊ณต")
# โ
ํ์ด์ง ๋ณธ๋ฌธ์ ํฌํจ๋ ํ
์คํธ๋ก ํ์
body_text = driver.find_element(By.TAG_NAME, "body").text
if "์๋
ํ์ธ์" in body_text or "๋" in body_text:
print("๋ก๊ทธ์ธ ์ฑ๊ณต")
โ ๏ธ ์ฃผ์๏ผ ํ์ ์ ์ฌ์ฉํ๋ ํ ์คํธ๋ ์ฌ์ดํธ์ ๋ฐ๋ผ ๋ค๋ฆ ๋๋ค. ์ค์ ๋ก ๋ก๊ทธ์ธ ํ ํ์ด์ง๋ฅผ ํ์ธํด์ ํ์คํ ํ์๋๋ ํ ์คํธ๋ฅผ ์ ํํ์ธ์.
์ ๋ฆฌ
์ด ๊ธ์์๋ ์๋๋ฐ์ ์นด๋ฉ๋ผ ํ์๊ฐ์ ํผ์ Python ร Selenium์ผ๋ก ์๋ํํ๋ ์คํฌ๋ฆฝํธ๋ฅผ ํด์คํ์ต๋๋ค.
์คํฌ๋ฆฝํธ ์คํ ํ ๋ฐ์คํฌํฑ์ yodobashi_signup_logs ํด๋๋ฅผ ์ด๋ฉด ๋ก๊ทธ ํ์ผ๊ณผ ์คํฌ๋ฆฐ์ท์ด ํ์์คํฌํ์ ํจ๊ป ์๋ ์ ์ฅ๋์ด ์์ต๋๋ค. ์ด๊ฒ์ด ๊ทธ๋๋ก ํ
์คํธ ์๋น๋์ค๋ก ํ์ฉ๋ฉ๋๋ค.
โฒ ์๋ ์ ์ฅ๋ ๋ก๊ทธ ํด๋์ ๋ด์ฉ. ๋ก๊ทธ ํ์ผ + ์คํฌ๋ฆฐ์ท 4์ฅ์ด ํ์์คํฌํ์ ํจ๊ป ์ ๋ฆฌ๋์ด ์์
| ๋ณต์ ์ ๋ ํฐ ํด๋ฐฑ ์ค๊ณ | XPath๋ฅผ ๋ณต์ ํจํด์ผ๋ก ์ค๋นํ์ฌ ๊ฒฌ๊ณ ํ ์์ ํ์์ ์คํ |
| ๋ก๊ทธ + ์คํฌ๋ฆฐ์ท | ์คํ ์ด๋ ฅ์ ์ถ์ ๊ฐ๋ฅํ๊ฒ ํ์ฌ ๋๋ฒ๊น ๊ณต์๋ฅผ ์ ๊ฐ |
| ๊ฐ์ โ ๋ก๊ทธ์์ โ ๋ก๊ทธ์ธ ์ผ๊ด ํ๋ก์ฐ | ๊ฐ์ ์๋ฃ๋ฟ๋ง ์๋๋ผ ๋ก๊ทธ์ธ ๊ฐ๋ฅ ์ํ๊น์ง ๊ฒ์ฆ |
| ํด๋์ค ์ค๊ณ์ ์ํ ์ฌ์ฌ์ฉ์ฑ | ๊ฐ ๊ธฐ๋ฅ์ด ๋ ๋ฆฝ๋ ๋ฉ์๋๋ก ๋ถ๋ฆฌ๋์ด ์์ด ํ์ฅ์ด ์ฌ์ |
QA ์์ง๋์ด๋ก์ “๋งค๋ฒ ์๋์ผ๋ก ํผ์ ์ฑ์ฐ๋ ๊ฒ์ ํ๊ณ”๋ผ๋ ๊ณผ์ ์ ๋ํด ์ค์ ํ์ฅ์์ ์ธ ์ ์๋ ์์ค์ ์๋ํ๋ฅผ ๋ชฉํ๋ก ์ค๊ณํ์ต๋๋ค. ๊ผญ GitHub์ ์ฝ๋๋ฅผ ์ฐธ๊ณ ํ์ฌ ์ฌ๋ฌ๋ถ์ ํ๋ก์ ํธ์ ๋ง๊ฒ ์ปค์คํฐ๋ง์ด์ฆํด ๋ณด์ธ์!

