Playwright + pytest-bdd์—์„œ POM ์ ์šฉ๊ธฐ

onyu
  • #qa
  • #์ž๋™ํ™”
  • #bdd
  • #playwright
  • #pom

๋“ค์–ด๊ฐ€๋ฉฐ

์•ˆ๋…•ํ•˜์„ธ์š”, ๋…ธ๋จธ์Šค QAํŒ€์˜ ๋ฐ•์˜จ์œ  ์ž…๋‹ˆ๋‹ค.
์ €ํฌ ํŒ€์€ Playwright + Python + pytest-bdd ํ™˜๊ฒฝ์—์„œ E2E ํ…Œ์ŠคํŠธ ์ž๋™ํ™”๋ฅผ ์ง„ํ–‰ํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ํ…Œ์ŠคํŠธ ์ฝ”๋“œ๊ฐ€ ์ ์  ๋Š˜์–ด๋‚˜๋ฉด์„œ ๋งค๋ฒˆ UI๊ฐ€ ์ˆ˜์ •๋  ๋•Œ๋งˆ๋‹ค ํ…Œ์ŠคํŠธ๊ฐ€ ๊นจ์กŒ๊ณ , ๋กœ์ผ€์ดํ„ฐ๊ฐ€ ์—ฌ๊ธฐ์ €๊ธฐ ํฉ์–ด์ ธ ์žˆ์–ด์„œ ์ˆ˜์ •ํ•˜๋Š” ๊ฒƒ๋„ ์ผ์ด์—ˆ์Šต๋‹ˆ๋‹ค.

์ด ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด POM ํŒจํ„ด์„ ๋„์ž…ํ–ˆ๊ณ , ์ด ๊ธ€์—์„œ๋Š” POM ํŒจํ„ด์ด ๋ฌด์—‡์ธ์ง€, ์žฅ๋‹จ์ ์€ ๋ฌด์—‡์ธ์ง€, ๊ทธ๋ฆฌ๊ณ  ์ €ํฌ ํŒ€์ด ์–ด๋–ป๊ฒŒ ์ „ํ™˜ํ–ˆ๋Š”์ง€ ๊ณต์œ ํ•˜๊ณ ์ž ํ•ฉ๋‹ˆ๋‹ค.


1. Page Object Model(POM)์ด๋ž€?

Page Object Model์€ ์›น ํŽ˜์ด์ง€๋ฅผ ๊ฐ์ฒด๋กœ ์ถ”์ƒํ™”ํ•˜๋Š” ํŒจํ„ด์ž…๋‹ˆ๋‹ค.
๊ฐ ํŽ˜์ด์ง€(๋˜๋Š” ์ปดํฌ๋„ŒํŠธ)๋ฅผ ํด๋ž˜์Šค๋กœ ๋งŒ๋“ค๊ณ , ํ•ด๋‹น ํŽ˜์ด์ง€์˜ ์š”์†Œ(๋กœ์ผ€์ดํ„ฐ)์™€ ๋™์ž‘(๋ฉ”์„œ๋“œ)์„ ํ•œ๊ณณ์— ๋ชจ์•„ ๊ด€๋ฆฌํ•ฉ๋‹ˆ๋‹ค.

pom

์›์น™์€ ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค:

  • ๋‹จ์ผ ์ฑ…์ž„: ๊ฐ Page ํด๋ž˜์Šค๋Š” ํ•ด๋‹น ํŽ˜์ด์ง€์˜ ๋™์ž‘๋งŒ ๋‹ด๋‹น
  • ๊ด€์‹ฌ์‚ฌ ๋ถ„๋ฆฌ: ๋กœ์ผ€์ดํ„ฐ์™€ ์ƒํ˜ธ์ž‘์šฉ ๋กœ์ง์„ Page ํด๋ž˜์Šค์—์„œ ๊ด€๋ฆฌํ•˜์—ฌ ํ…Œ์ŠคํŠธ ์ฝ”๋“œ์™€ ๋ถ„๋ฆฌ
  • ์žฌ์‚ฌ์šฉ์„ฑ: ๋™์ผํ•œ ํŽ˜์ด์ง€ ๋™์ž‘์„ ์—ฌ๋Ÿฌ ํ…Œ์ŠคํŠธ์—์„œ ์žฌ์‚ฌ์šฉ

2. POM์˜ ์žฅ๋‹จ์ 

์žฅ์ 

ํ•ญ๋ชฉ์„ค๋ช…
์œ ์ง€๋ณด์ˆ˜ ์šฉ์ดUI ๋ณ€๊ฒฝ ์‹œ ํ•ด๋‹น Page ํด๋ž˜์Šค๋งŒ ์ˆ˜์ •ํ•˜๋ฉด ๋จ
์ฝ”๋“œ ์žฌ์‚ฌ์šฉ๋™์ผํ•œ ํŽ˜์ด์ง€ ๋™์ž‘์„ ์—ฌ๋Ÿฌ ํ…Œ์ŠคํŠธ์—์„œ ์žฌ์‚ฌ์šฉ ๊ฐ€๋Šฅ
๊ฐ€๋…์„ฑ ํ–ฅ์ƒํ…Œ์ŠคํŠธ ์ฝ”๋“œ์—์„œ ๋กœ์ผ€์ดํ„ฐ๊ฐ€ ์‚ฌ๋ผ์ง€๊ณ  ์˜๋„๊ฐ€ ๋ช…ํ™•ํ•ด์ง
๋””๋ฒ„๊น… ์šฉ์ด์‹คํŒจ ์ง€์ ์„ Page ๋‹จ์œ„๋กœ ๋น ๋ฅด๊ฒŒ ํŒŒ์•… ๊ฐ€๋Šฅ

๋‹จ์ 

ํ•ญ๋ชฉ์„ค๋ช…
์ดˆ๊ธฐ ๊ตฌ์ถ• ๋น„์šฉํด๋ž˜์Šค ๊ตฌ์กฐ๋ฅผ ์„ค๊ณ„ํ•˜๊ณ  ๋งŒ๋“œ๋Š” ๋ฐ ์‹œ๊ฐ„์ด ํ•„์š”
๊ณผ๋„ํ•œ ์ถ”์ƒํ™” ์œ„ํ—˜๋‹จ์ˆœํ•œ ํ…Œ์ŠคํŠธ์—๋„ ๋ถˆํ•„์š”ํ•œ ํด๋ž˜์Šค๋ฅผ ๋งŒ๋“ค ์ˆ˜ ์žˆ์Œ

POM์ด ์ ํ•ฉํ•œ ๊ฒฝ์šฐ

  • ํ…Œ์ŠคํŠธ ์ผ€์ด์Šค๊ฐ€ ๊ณ„์† ๋Š˜์–ด๋‚˜๋Š” ํ”„๋กœ์ ํŠธ
  • ์—ฌ๋Ÿฌ ํ…Œ์ŠคํŠธ์—์„œ ๋™์ผํ•œ ํŽ˜์ด์ง€/์ปดํฌ๋„ŒํŠธ ์‚ฌ์šฉ
  • UI ๋ณ€๊ฒฝ์ด ์žฆ์€ ์„œ๋น„์Šค
  • ํŒ€ ๋‹จ์œ„๋กœ ํ…Œ์ŠคํŠธ ์ฝ”๋“œ ์ž‘์„ฑ

POM์ด ๊ณผํ•œ ๊ฒฝ์šฐ

  • ์ผํšŒ์„ฑ ํ…Œ์ŠคํŠธ
  • ๋กœ์ผ€์ดํ„ฐ๊ฐ€ ์ ์€ ๋‹จ์ˆœํ•œ ํ…Œ์ŠคํŠธ
  • ํ”„๋กœํ† ํƒ€์ž…/PoC ๋‹จ๊ณ„

3. ๊ธฐ์กด ๋ฐฉ์‹์—์„œ POM์œผ๋กœ ์ „ํ™˜

3-1. ๊ธฐ์กด ๋ฐฉ์‹์˜ ๋ฌธ์ œ์ 

Fromm/web/store/steps/
โ”œโ”€โ”€ login.py           # ๋กœ๊ทธ์ธ ๊ด€๋ จ ์Šคํ…
โ””โ”€โ”€ ...
@when('Store [๋กœ๊ทธ์ธ] ๋ฒ„ํŠผ ํด๋ฆญ')
def click_login_btn(store_page: Page):
    store_page.get_by_text('๋กœ๊ทธ์ธ', exact=True).click()
    
@then('Store [๋กœ๊ทธ์ธ] ๋ฒ„ํŠผ ํ™œ์„ฑํ™”')
def expect_login_btn_enabled(store_page: Page):
    expect(store_page.get_by_text('๋กœ๊ทธ์ธ', exact=True)).to_be_enabled()

๋ฌธ์ œ์ :

  • ๋กœ์ผ€์ดํ„ฐ๊ฐ€ ์—ฌ๋Ÿฌ ํŒŒ์ผ์— ํ•˜๋“œ์ฝ”๋”ฉ๋˜์–ด ์ค‘๋ณต ๋ฐœ์ƒ
  • UI ๋ณ€๊ฒฝ ์‹œ ๋ชจ๋“  ํŒŒ์ผ์„ ์ˆ˜์ •ํ•ด์•ผ ํ•จ

3-2. POM ์ ์šฉ ํ›„ ๊ตฌ์กฐ

Fromm/web/
โ”œโ”€โ”€ common/
โ”‚   โ”œโ”€โ”€ base.py           # ActionBase, ExpectBase๋ฅผ ์กฐํ•ฉํ•˜๋Š” ๊ธฐ๋ฐ˜ ํด๋ž˜์Šค
โ”‚   โ”œโ”€โ”€ action_base.py    # ์•ก์…˜ ๋ฉ”์„œ๋“œ (click, fill ๋“ฑ)
โ”‚   โ””โ”€โ”€ expect_base.py    # ๊ฒ€์ฆ ๋ฉ”์„œ๋“œ (expect ๋“ฑ)
โ””โ”€โ”€ store/
    โ”œโ”€โ”€ pages/
    โ”‚   โ”œโ”€โ”€ login_page.py
    โ”‚   โ”œโ”€โ”€ goods_page.py
    โ”‚   โ””โ”€โ”€ ...
    โ”œโ”€โ”€ steps/
    โ”‚   โ”œโ”€โ”€ login_steps.py
    โ”‚   โ””โ”€โ”€ ...
    โ””โ”€โ”€ components/
        โ”œโ”€โ”€ header.py
        โ””โ”€โ”€ menu.py

3-3. Base ํด๋ž˜์Šค ์„ค๊ณ„

์•ก์…˜๊ณผ ๊ฒ€์ฆ ์ฑ…์ž„์„ ๋ถ„๋ฆฌํ•˜์—ฌ Base ํด๋ž˜์Šค๋กœ ์กฐํ•ฉํ–ˆ์Šต๋‹ˆ๋‹ค.
๋ชจ๋“  Page ํด๋ž˜์Šค๋Š” ์ด Base๋ฅผ ์ƒ์†๋ฐ›์•„ ๊ณตํ†ต ๋ฉ”์„œ๋“œ๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

class Base(ActionBase, ExpectBase, LogMixin):
    def __init__(self, page: Page):
        self.page = page
    ...

์ด๋ ‡๊ฒŒ ๋ถ„๋ฆฌํ•œ ์ด์œ ๋Š”, Page ํด๋ž˜์Šค์—์„œ Playwright API๋ฅผ ์ง์ ‘ ํ˜ธ์ถœํ•˜์ง€ ์•Š๊ธฐ ์œ„ํ•ด์„œ์ž…๋‹ˆ๋‹ค.
๋งŒ์•ฝ Base ์—†์ด Page ํด๋ž˜์Šค๋งˆ๋‹ค self.page.locator(selector).click() ๊ฐ™์€ ์ฝ”๋“œ๋ฅผ ์ง์ ‘ ์ž‘์„ฑํ•˜๋ฉด, Playwright API๊ฐ€ ๋ณ€๊ฒฝ๋  ๋•Œ ๋ชจ๋“  Page ํด๋ž˜์Šค๋ฅผ ์ˆ˜์ •ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
Base์—์„œ ํ•œ ๋ฒˆ๋งŒ ๊ฐ์‹ธ๋‘๋ฉด ์ˆ˜์ • ํฌ์ธํŠธ๊ฐ€ ํ•œ ๊ณณ์œผ๋กœ ์ค„์–ด๋“ญ๋‹ˆ๋‹ค.

ActionBase๋Š” click, fill ๋“ฑ ํ™”๋ฉด ์กฐ์ž‘ ๋ฉ”์„œ๋“œ๋ฅผ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.

class ActionBase:
    def click(self, target: str | Locator, **kwargs) -> None:
        if isinstance(target, Locator):
            target.click()
        else:
            self.page.locator(target, **kwargs).click()

    def fill(self, target: str | Locator, value: str, **kwargs) -> None:
        if isinstance(target, Locator):
            target.fill(value)
        else:
            self.page.locator(target, **kwargs).fill(value)

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

ExpectBase๋Š” expect_visible, expect_enabled ๋“ฑ ๊ฒ€์ฆ ๋ฉ”์„œ๋“œ๋ฅผ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.

class ExpectBase:
    def expect_visible(self, selector: str, **kwargs) -> None:
        expect(self.page.locator(selector, **kwargs)).to_be_visible()

    def expect_enabled(self, selector: str, **kwargs) -> None:
        expect(self.page.locator(selector, **kwargs)).to_be_enabled()

์ด๋ ‡๊ฒŒ ๋ž˜ํ•‘ํ•ด๋‘๋ฉด ๊ฒ€์ฆ ๋ฐฉ์‹์˜ ์ผ๊ด€์„ฑ๋„ ํ™•๋ณดํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
์˜ˆ๋ฅผ ๋“ค์–ด, ๋ฒ„ํŠผ์ด ํ™œ์„ฑํ™” ์ƒํƒœ์ธ์ง€ ๊ฒ€์ฆํ•  ๋•Œ ๋ˆ„๊ตฐ๊ฐ€๋Š” to_be_enabled()๋ฅผ ์“ฐ๊ณ , ๋ˆ„๊ตฐ๊ฐ€๋Š” not_to_be_disabled()๋ฅผ ์“ธ ์ˆ˜ ์žˆ๋Š”๋ฐ, expect_enabled๋กœ ํ†ต์ผํ•ด๋‘๋ฉด ์ด๋Ÿฐ ๊ฑฑ์ • ์—†์ด ์ฝ”๋“œ๊ฐ€ ์ผ๊ด€์„ฑ ์žˆ๊ฒŒ ์ž‘์„ฑ๋ฉ๋‹ˆ๋‹ค.

๋•๋ถ„์— Page ํด๋ž˜์Šค์—์„œ๋Š” self.click(selector), self.expect_visible(selector) ์ฒ˜๋Ÿผ ๊ฐ„๊ฒฐํ•˜๊ฒŒ ํ˜ธ์ถœํ•  ์ˆ˜ ์žˆ๊ณ , Playwright์˜ ์„ธ๋ถ€ ๊ตฌํ˜„์„ ์•Œ ํ•„์š”๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค.

3-4. Page ํด๋ž˜์Šค ์ž‘์„ฑ

class LoginPage(Base):
    @property
    def LOGIN_BTN(self):
        return self.page.get_by_text('๋กœ๊ทธ์ธ', exact=True)

    def click_login_btn(self) -> None:
        self.click(self.LOGIN_BTN)

    def expect_login_btn_enabled(self) -> None:
        self.expect_enabled(self.LOGIN_BTN)

3-5. Step ์ •์˜

Step ํ•จ์ˆ˜๋Š” โ€œ๋ฌด์—‡์„ ํ•˜๋Š”์ง€โ€๋งŒ ํ‘œํ˜„ํ•˜๊ณ , โ€œ์–ด๋–ป๊ฒŒ ํ•˜๋Š”์ง€โ€๋Š” Page ํด๋ž˜์Šค๊ฐ€ ๋‹ด๋‹นํ•ฉ๋‹ˆ๋‹ค.

@when('Store [๋กœ๊ทธ์ธ] ๋ฒ„ํŠผ ํด๋ฆญ')
def click_login_btn(store_page: Page):
    LoginPage(store_page).click_login_btn()

@then('Store [๋กœ๊ทธ์ธ] ๋ฒ„ํŠผ ํ™œ์„ฑํ™”')
def expect_login_btn_enabled(store_page: Page):
    LoginPage(store_page).expect_login_btn_enabled()

4. pytest-bdd ํ™˜๊ฒฝ์—์„œ์˜ POM ์ ์šฉ ํฌ์ธํŠธ

์ผ๋ฐ˜์ ์ธ POM ์˜ˆ์ œ๋Š” ํ•˜๋‚˜์˜ ํ…Œ์ŠคํŠธ ํ•จ์ˆ˜ ์•ˆ์—์„œ Page ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•˜๊ณ  ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.
ํ•˜์ง€๋งŒ pytest-bdd์—์„œ๋Š” Step ํ•จ์ˆ˜๊ฐ€ ๊ฐ๊ฐ ๋ถ„๋ฆฌ๋˜์–ด ์žˆ๊ธฐ ๋•Œ๋ฌธ์—, POM์„ ์ ์šฉํ•  ๋•Œ ์ถ”๊ฐ€์ ์ธ ๊ณ ๋ ค๊ฐ€ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.

4-1. Feature โ†’ Step โ†’ Page Object ๊ตฌ์กฐ

pytest-bdd๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์ผ๋ฐ˜์ ์ธ POM๋ณด๋‹ค ๋ ˆ์ด์–ด๊ฐ€ ํ•˜๋‚˜ ๋” ์ƒ๊น๋‹ˆ๋‹ค. ๊ตฌ์กฐ

์—ฌ๊ธฐ์„œ Step๊ณผ Page์˜ ์—ญํ•  ๊ฒฝ๊ณ„๋ฅผ ๋ช…ํ™•ํžˆ ํ•˜๋Š” ๊ฒƒ์ด ์ค‘์š”ํ•ฉ๋‹ˆ๋‹ค.

  • Page: ํ™”๋ฉด ์กฐ์ž‘, ๋กœ์ผ€์ดํ„ฐ ๊ด€๋ฆฌ, ๊ฐ’ ์ƒ์„ฑ ๋ฐ return
  • Step: Page ํ˜ธ์ถœ, ๊ฒฐ๊ณผ๋ฅผ ๊ณต์œ  fixture์— ์ €์žฅ, ํ…Œ์ŠคํŠธ ํ™˜๊ฒฝ ์ •๋ณด(ํŒŒ์ผ ๊ฒฝ๋กœ ๋“ฑ) ์ „๋‹ฌ

4-2. Page ๊ฐ์ฒด๋ฅผ fixture๋กœ ์ฃผ์ž…๋ฐ›๋Š” ๊ตฌ์กฐ

pytest-bdd์˜ Step ํ•จ์ˆ˜๋Š” pytest fixture๋ฅผ ํ†ตํ•ด ๋ธŒ๋ผ์šฐ์ € Page๋ฅผ ์ฃผ์ž…๋ฐ›์Šต๋‹ˆ๋‹ค.
Step์—์„œ ์ง์ ‘ Page๋ฅผ ์ƒ์„ฑํ•˜๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋ผ, conftest.py์—์„œ ์„ค์ •ํ•œ fixture๋ฅผ ๋ฐ›์•„์„œ Page Object์— ๋„˜๊ธฐ๋Š” ๊ตฌ์กฐ์ž…๋‹ˆ๋‹ค.

# conftest.py
@pytest.fixture
def store_page(browser) -> Page:
    context = browser.new_context()
    page = context.new_page()
    page.goto('https://example.com/store')
    return page
# step ํ•จ์ˆ˜์—์„œ fixture๋ฅผ ๋ฐ›์•„ Page Object์— ์ „๋‹ฌ
@when('Store [๋กœ๊ทธ์ธ] ๋ฒ„ํŠผ ํด๋ฆญ')
def click_login_btn(store_page: Page):
    LoginPage(store_page).click_login_btn()

4-3. Step ๊ฐ„ ๋ฐ์ดํ„ฐ ๊ณต์œ 

pytest-bdd์—์„œ ๊ฐ€์žฅ ํฐ ์ฐจ์ด์ ์€ Step ํ•จ์ˆ˜๊ฐ€ ๊ฐ๊ฐ ๋…๋ฆฝ์ ์ด๋ผ๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.
์ผ๋ฐ˜ pytest์—์„œ๋Š” ํ•˜๋‚˜์˜ ํ…Œ์ŠคํŠธ ํ•จ์ˆ˜ ์•ˆ์—์„œ ๋ณ€์ˆ˜๋ฅผ ์ž์œ ๋กญ๊ฒŒ ๊ณต์œ ํ•  ์ˆ˜ ์žˆ์ง€๋งŒ, pytest-bdd์—์„œ๋Š” Step A์—์„œ ๋งŒ๋“  ๊ฐ’์„ Step B์—์„œ ์‚ฌ์šฉํ•˜๋ ค๋ฉด ๊ณต์œ  fixture๊ฐ€ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.

# conftest.py - ๊ฐ’์„ ๊ณต์œ ํ•  ์ €์žฅ์†Œ fixture
@pytest.fixture
def shared_values():
    random_text = uuid4().hex[:6]
    return {'random_text': random_text}
# Step A: Page๊ฐ€ ๋งŒ๋“  ๊ฐ’์„ ๊ณต์œ  ์ €์žฅ์†Œ์— ์ €์žฅ
@when('Store ํšŒ์›๊ฐ€์ž… ์‹œ ๋‹‰๋„ค์ž„ ์ž…๋ ฅ')
def input_nickname(store_page: Page, shared_values):
    shared_values['nickname'] = SignupPage(store_page).input_nickname(
        shared_values['random_text']
    )

# Step B: ์ €์žฅ์†Œ์—์„œ ๊บผ๋‚ด์„œ ์‚ฌ์šฉ
@then('Store ๋งˆ์ดํŽ˜์ด์ง€์—์„œ ๋‹‰๋„ค์ž„ ํ™•์ธ')
def check_nickname(store_page: Page, shared_values):
    nickname = shared_values['nickname']
    MyPage(store_page).expect_nickname(nickname)

์ด ํŒจํ„ด์—์„œ Page ํด๋ž˜์Šค๋Š” ๊ฐ’์„ ์ƒ์„ฑํ•˜๊ณ  returnํ•˜๋Š” ์—ญํ• ๋งŒ ํ•˜๊ณ , Step์ด ๊ทธ ๊ฐ’์„ ๊ณต์œ  ์ €์žฅ์†Œ์— ์ €์žฅํ•˜๋Š” ์—ญํ• ์„ ๋‹ด๋‹นํ•ฉ๋‹ˆ๋‹ค. ์ด๋ ‡๊ฒŒ ํ•˜๋ฉด Page ํด๋ž˜์Šค๋Š” pytest-bdd์˜ fixture ๊ตฌ์กฐ๋ฅผ ์•Œ ํ•„์š” ์—†์ด ์ˆœ์ˆ˜ํ•˜๊ฒŒ ํ™”๋ฉด ์กฐ์ž‘์—๋งŒ ์ง‘์ค‘ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.


๋งˆ๋ฌด๋ฆฌํ•˜๋ฉฐ

POM ํŒจํ„ด์„ ๋„์ž…ํ•œ ํ›„ ๋‹ค์Œ๊ณผ ๊ฐ™์€ ํšจ๊ณผ๋ฅผ ์ฒด๊ฐํ•  ์ˆ˜ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค.

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

๋ฌผ๋ก  ์ „ํ™˜ ๊ณผ์ •์ด ์ˆœํƒ„ํ•˜์ง€๋งŒ์€ ์•Š์•˜์Šต๋‹ˆ๋‹ค. ์ฒ˜์Œ์—๋Š” ๊ธฐ์กด Step ํŒŒ์ผ์— ๋กœ์ผ€์ดํ„ฐ์™€ ๋กœ์ง์ด ๋’ค์„ž์—ฌ ์žˆ์–ด์„œ, ์–ด๋””๊นŒ์ง€๋ฅผ Page ํด๋ž˜์Šค๋กœ ์˜ฎ๊ธฐ๊ณ  ์–ด๋””๊นŒ์ง€๋ฅผ Step์— ๋‚จ๊ธธ์ง€ ๊ฒฝ๊ณ„๋ฅผ ์žก๋Š” ๊ฒŒ ์–ด๋ ค์› ์Šต๋‹ˆ๋‹ค.
๋˜ํ•œ ๊ธฐ์กด ํ…Œ์ŠคํŠธ๋ฅผ ์œ ์ง€ํ•˜๋ฉด์„œ ์ ์ง„์ ์œผ๋กœ ์ „ํ™˜ํ•ด์•ผ ํ–ˆ๊ธฐ ๋•Œ๋ฌธ์—, ์ €ํฌ ํŒ€์€ ํ•œ ํŽ˜์ด์ง€๋ถ€ํ„ฐ ์ „ํ™˜ํ•˜๊ณ , ํŒจํ„ด์ด ์ต์ˆ™ํ•ด์ง€๋ฉด ๋‹ค์Œ ํŽ˜์ด์ง€๋กœ ๋„˜์–ด๊ฐ€๋Š” ๋ฐฉ์‹์„ ํƒํ–ˆ๊ณ , ์ด ๋ฐฉ์‹์ด ํ›จ์”ฌ ํšจ๊ณผ์ ์ด์—ˆ์Šต๋‹ˆ๋‹ค.

๊ธด ๊ธ€ ์ฝ์–ด์ฃผ์…”์„œ ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค. ๋น„์Šทํ•œ ๊ณ ๋ฏผ์„ ํ•˜๊ณ  ๊ณ„์‹  ๋ถ„๋“ค๊ป˜ ์กฐ๊ธˆ์ด๋‚˜๋งˆ ๋„์›€์ด ๋˜์—ˆ์œผ๋ฉด ํ•ฉ๋‹ˆ๋‹ค.

โ† ๋ชฉ๋ก์œผ๋กœ ๋Œ์•„๊ฐ€๊ธฐ

Art Changes Life

๋…ธ๋จธ์Šค์™€ ํ•จ๊ป˜ ์—”ํ„ฐํ…Œํฌ ์‚ฐ์—…์„ ํ˜์‹ ํ•ด๋‚˜๊ฐˆ ๋ฉค๋ฒ„๋ฅผ ์ฐพ์Šต๋‹ˆ๋‹ค.

์ฑ„์šฉ ์ค‘์ธ ๊ณต๊ณ  ๋ณด๊ธฐ