E2E ํ ์คํธ์ ๋์ดํธ์์น
๋์ดํธ์์น๋ฅผ ์๊ฐํ๊ธฐ ์ ์ E2E ํ ์คํธ์ ์ ์๋ถํฐ ์ ๋ ๋์ ์น๋๋ผ์ด๋ฒ ๋ฑ ๊ธฐ๋ณธ ๊ฐ๋ ๋ถํฐ ๊ฐ๋จํ ์๊ฐํ๊ฒ ๋ค.
E2E ํ ์คํธ
์ ์
์ํํธ์จ์ด ํ ์คํธ๋ ํ ์คํธ์ ๊ท๋ชจ(๋ ๋ฒจ)์ ๋ฐ๋ผ ์ ๋ ํ ์คํธ, ํตํฉ ํ ์คํธ, ์์คํ ํ ์คํธ, ์ธ์ ํ ์คํธ ์ด๋ ๊ฒ 4๊ฐ์ง๋ก ๋ถ๋ฅํ๋ค. ์ฌ๊ธฐ์์ E2E ํ ์คํธ๋ ์์คํ ํ ์คํธ์ ์ํ๋ค.
E2E(End-to-End) ํ ์คํธ๋ ์ ์ฒด ์์คํ ์ด ์ ๋๋ก ์๋ํ๋์ง ํ์ธ ํ๊ธฐ ์ํ ํ ์คํธ๋ก ์๋๋ฆฌ์ค ํ ์คํธ, ๊ธฐ๋ฅ ํ ์คํธ, ํตํฉ ํ ์คํธ, GUI ํ ์คํธ๋ฅผ ํ๋๋ฐ ์ฌ์ฉํ๋ค. API์์ ์ฐ๋๋ ํ ์คํธ ํญ๋ชฉ์ ํฌํจ๋๊ธฐ ๋๋ฌธ์ ์ผ๋ฐ์ ์ผ๋ก ๋ชฉ(Mock)์ด๋ ์คํ (Stub)๊ณผ ๊ฐ์ ํ ์คํธ ๋๋ธ์ ์ฌ์ฉํ์ง ์์ผ๋ฉฐ ์ต๋ํ ์ค์ ์์คํ ์ ์ฌ์ฉํ๋ ์ฌ์ฉ์ ๊ด์ ์์ ์๋ฎฌ๋ ์ด์ ํ๋ค. ๊ทธ๋์ ํ ์คํธ ์๋๊ฐ ์๋น์ค ๊ท๋ชจ์ ๋ฐ๋ผ ์๋นํ ๋๋ฆด ์ ์๊ธฐ ๋๋ฌธ์ ์ ๋ ํ ์คํธ๋ ๊ธฐ๋ฅ ํ ์คํธ๋ฅผ ์ํ ์ผ๋ฐ์ ์ธ ํ ์คํธ ์๋ํ์ ์์คํ ํ ์คํธ๋ฅผ ์ํ E2E ํ ์คํธ ์๋ํ๋ฅผ ํจ๊ป ๊ตฌ์ฑํ๋ค.
E2E ํ ์คํธ ํ๋ ์์ํฌ
E2E ํ ์คํธ ํ๋ ์์ํฌ๋ ๋ค์ํ ์ข ๋ฅ๊ฐ ์๋๋ฐ, ํฌ๊ฒ ํค๋๋ฆฌ์ค ๋ธ๋ผ์ฐ์ ๋ฅผ ์์กดํ๋ ๊ฒ๊ณผ ์ ๋ ๋์ ์น๋๋ผ์ด๋ฒ๋ฅผ ์์กดํ๋ ๊ฒ์ผ๋ก ๋๋ ์ ์๋ค. ์ ๋ ๋์ ์น๋๋ผ์ด๋ฒ๋ ๋ค์ ์ ์์ ์์ธํ ์ค๋ช ํ๋ค.
ํค๋๋ฆฌ์ค ๋ธ๋ผ์ฐ์ ๋ ์ปค๋งจ๋ ๋ผ์ธ ๋ช ๋ น์ด๋ก ์กฐ์ํ ์ ์๋ ํ๋ฉด์ด ์๋ ๋ธ๋ผ์ฐ์ ๋ก Jsdom ๊ธฐ๋ฐ์ ์ข๋น(Zombie.js), ์นํท ์์ง ๊ธฐ๋ฐ์ ํฌํ (Pantom.js), ๊ฒ์ฝ ์์ง ๊ธฐ๋ฐ์ ์ฌ๋ฆฌ๋จธ(Slimer.js) ๋ฑ์ด ์๋ค. ์ ์๋ ค์ง ์บ์คํผ(Casper.js)๋ ํฌํ ๊ณผ ์ฌ๋ฆฌ๋จธ๋ฅผ ์กฐ๊ธ ๋ ์ฌ์ฉํ๊ธฐ ์ฝ๊ฒ ๋ง๋ค์ด ๋์ ์ ํธ๋ฆฌํฐ ๋๊ตฌ๋ค. ํค๋๋ฆฌ์ค ๋ธ๋ผ์ฐ์ ๋ ๊ธฐ๋ณธ์ ์ผ๋ก ํฌ๋ก์ค ๋ธ๋ผ์ฐ์ง ํ ์คํธ๊ฐ ๋ถ๊ฐ๋ฅํ๋ฉฐ ์ด์ฐํธ(Assert)๋ ๋ด์ฅํ๊ณ ์์ง ์๊ธฐ ๋๋ฌธ์ ํ์ํ๋ค๋ฉด ์ถ๊ฐ๋ฅผ ํด์ผํ๋ค.
์ ๋ ๋์ ์น๋๋ผ์ด๋ฒ๋ฅผ ์์กดํ๋ ํ๋ ์์ํฌ๋ก๋ webdriver.io, ํ์ปด๋ฒ(Cucumber.js), ํ๋กํธ๋ํฐ, ๋์ดํธ์์น ๋ฑ์ด ์๋ค. ์ด๋ค์ ํฌ๋ก์ค ๋ธ๋ผ์ฐ์ง ํ ์คํธ๊ฐ ๊ฐ๋ฅํ๊ณ ์ด์ฐํธ๋ ๋ด์ฅํ๊ณ ์๋ค. ๋จ, ๊ฐ ํ๋ ์์ํฌ ๋ง๋ค ๋ด์ฅํ๊ณ ์๋ ์ด์ฐํธ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ ๋ค๋ฅด๋ค.
์ ๋ ๋์ ์น๋๋ผ์ด๋ฒ
๋์ดํธ์์น๋ ์ ๋ ๋์ ์น๋๋ผ์ด๋ฒ(Selenium WebDriver) API๋ฅผ ์ฌ์ฉํด ๊ฐ๋ฐ๋ E2E ํ ์คํธ ํ๋ ์์ํฌ์ด๊ธฐ ๋๋ฌธ์ ๋ณธ๊ฒฉ์ ์ผ๋ก ์ฌ์ฉํด๋ณด๊ธฐ ์ ์ ์ ๋ ๋์๊ณผ ์น๋๋ผ์ด๋ฒ๋ฅผ ๋จผ์ ์ดํดํ ํ์๊ฐ ์๋ค.
์ ๋ ๋์ ์น๋๋ผ์ด๋ฒ์ ์๋ ์ด๋ฆ์ ์ ๋ ๋์(๋๋ ์ ๋ ๋์ 1.0)์ด์๋ค. ์ ๋ ๋์์ ์น ๋ธ๋ผ์ฐ์ ๋ฅผ ์ฌ์ฉํ์ฌ ์น ์ ํ๋ฆฌ์ผ์ด์ ์ ํ ์คํธํ๋ ์คํ ์์ค ๋๊ตฌ๋ค. ์ด๋ ์ฌ๋์ ์์ผ๋ก ์ง์ ์น ๋ธ๋ผ์ฐ์ ๋ฅผ ์กฐ์ํ๋ ๊ฒ์ด ์๋๋ผ ์์ฑ๋ ์คํฌ๋ฆฝํธ์ ๋ฐ๋ผ ์๋์ผ๋ก ์กฐ์ํ๋ค. ์ด๋ฌํ ๋ฐฉ๋ฒ์ ๋ธ๋ผ์ฐ์ ์๋ํ(Browser Automation)๋ผ๊ณ ํํํ๋ค.
์ ๋ ๋์์ ์์นด๊ณ ์ ์์นํ ์ํธ์ํฌ์ค(ThoughtWorks) ์ฌ์์ ๊ฐ๋ฐ์ ์์ํ๋ค. ์ํธ์ํฌ์ค๋ ๋งํด ํ์ธ๋ฌ(Martin Fowler)๊ฐ ์ํ ๊ทธ๋ฃน์ผ๋ก ์ ๋ช ํ๋ค.
์น๋๋ผ์ด๋ฒ๋ ์ ๋ ๋์์ ๋จ์ ์ ๋ณด์ํ๊ณ ์ ๊ตฌ๊ธ์ ์์ง๋์ด๋ค์ด ๊ฐ๋ฐํ๊ณ ์ฌ์ฉํ ๋ธ๋ผ์ฐ์ ์๋ ํ ์คํธ ๋๊ตฌ์ด๋ค. 2006๋ ๊ฒฝ ๊ตฌ๊ธ์์ ๊ทผ๋ฌด ์ค์ด๋ ์๋ชฌ ์คํ์ดํธ(Simon Stewart)๊ฐ ์ฃผ๋ํด ํ๋ก์ ํธ๋ฅผ ์์ํ๊ณ 2009๋ ์ ์ฒ์์ผ๋ก ๊ณต์ ๋ฐํํ๋ค.
<๊ทธ๋ฆผ 1 ์ ๋ ๋์ ํ๋ก์ ํธ์ ํ๋ฆ>
๊ณผ๊ฑฐ ์ ๋ ๋์์ ์์ฒด ์์ง์ธ ์ ๋ ๋์ RC(Remote Control)๋ฅผ ์ด์ฉํด ๋ธ๋ผ์ฐ์ ์ ํต์ ํ๋ค.
์ ๋ ๋์ RC๋ ์๋ฐ๋ ํ์ด์ฌ ๋ฑ์ ์ธ์ด๋ก ์คํฌ๋ฆฝํธ๋ฅผ ์์ฑํ๋ฉด ๊ทธ ์คํฌ๋ฆฝํธ๋ฅผ ๊ธฐ๋ฐ์ผ๋ก ๋ธ๋ผ์ฐ์ ๋ฅผ ์กฐ์ํ๋ ์๋ฐ์คํฌ๋ฆฝํธ๋ฅผ ์์ฑํ๊ณ ํด๋น ํ์ด์ง์ ์ฝ์ ํ ๋ธ๋ผ์ฐ์ ๋ฅผ ์กฐ์ํ๋ ๊ฐ๋จํ ๊ตฌ์กฐ์๋ค. ์ด๋ฌํ ๊ตฌ์กฐ๋ ๋ธ๋ผ์ฐ์ ์ ๋ณด์ ์ ์ฝ์ด๋ ์๋ฐ์คํฌ๋ฆฝํธ์ ํ๊ณ๋ก ์ธํด ์คํจ์ฑ์ด ๋จ์ด์ง๋ ๋จ์ ์ด ์์๋ค. ์ด ๋จ์ ์ด ์๋ชฌ ์คํ์ดํธ๊ฐ ์น๋๋ผ์ด๋ฒ๋ฅผ ๋ง๋ค๊ฒ ๋ ์ด์ ์ด๊ธฐ๋ ํ๋ค.
๊ทธ์ ๋ฐํด ์น๋๋ผ์ด๋ฒ๋ ๋ธ๋ผ์ฐ์ ์ ํ์ฅ ๊ธฐ๋ฅ๊ณผ OS์ ๊ธฐ๋ณธ ๊ธฐ๋ฅ ๋ฑ์ ์ด์ฉํ์ฌ ๋ธ๋ผ์ฐ์ ๋ฅผ ์กฐ์ํ๋ ๊ตฌ์กฐ์๋ค. ์ด๋ ์ ๋ ๋์ RC์ ๋จ์ ์ ์ถฉ์กฑํด์ค ์ ์๋ ๋ฐฉ์์ด์๋ค.
<๊ทธ๋ฆผ 2 ์ ๋ ๋์ ์น๋๋ผ์ด๋ฒ ๋ค์ด์ด๊ทธ๋จ>
์ด ๋ฐฉ์์ด ์ฑ๊ณตํ์ฌ ์ ๋ ๋์ RC์ ์น๋๋ผ์ด๋ฒ ํตํฉ์ด ์ด๋ฃจ์ด์ก๊ณ 2011๋ 7์์ ์ ๋ ๋์ ์น๋๋ผ์ด๋ฒ(๋๋ ์ ๋ ๋์ 2.0)๋ฅผ ๋ฆด๋ฆฌ์ฆํ๊ฒ ๋๋ค. ์ฆ, ํ์ฌ ์ฐ๋ฆฌ๊ฐ ์๊ณ ์๋ ์ ๋ ๋์์ ์น๋๋ผ์ด๋ฒ์ ํตํฉํ ๋ฒ์ ์ด๋ค.
๊ทธ๋ฆผ 2๋ฅผ ๋ณด๋ฉด ์ ์ ์๋ฏ์ด ์น๋๋ผ์ด๋ฒ๋ ๋ค์ํ ๋ธ๋ผ์ฐ์ ์ ํ๊ฒฝ์ ๋์ํด์ผํ๋๋ฐ, ๋ธ๋ผ์ฐ์ ๋ง๋ค ์ด๋ฅผ ์ํ API๊ฐ ๋ค๋ฅผ ๊ฒฝ์ฐ ๋ ๋ค๋ฅธ ๋ฌธ์ ๊ฐ ๋ฐ์ํ ์ ์๊ธฐ ๋๋ฌธ์ ํ์ฌ ํ์คํ๋ฅผ ์ ์ (W3C WebDriver) ์ค์ด๋ค.
ํ์ฌ ์ ๋ ๋์ ์น๋๋ผ์ด๋ฒ๋ ํ์ด์ฌ, ๋ฃจ๋น, ์๋ฐ, C# ๊ทธ๋ฆฌ๊ณ Node.js๋ฅผ ์ด์ฉํด ์น๋ธ๋ผ์ฐ์ ๋ ์กฐ์ํ ์ ์๋๋ก ๋ค์ํ API๋ฅผ ์ ๊ณตํ๊ณ ์๋ค. ํ์ง๋ง ์ ๋ ๋์ ์๋ฒ์ ์๋ฐ์คํฌ๋ฆฝํธ์ ๊ถํฉ์ด ์ข์ง ์๊ณ , ๋์ ์กฐ์ ํ๊ฑฐ๋ ์ ๋ ํ ํ๋๋ฐ ํ๊ณ๊ฐ ์์ด ์ ๋ ๋์ ์น๋๋ผ์ด๋ฒ์ ๋ ธ๋๋ฅผ ๋ฐ์ธ๋ฉํ์ฌ ๋ค์ํ ๊ธฐ๋ฅ์ ์ ๊ณตํ๋ ์ฌ๋ฌ๊ฐ์ง ํํ์ ํ๋ก์ ํธ๊ฐ ์๊ฒจ๋ฌ๋ค. ๊ทธ ์ค ์ ๋ช ํ ํ๋ก์ ํธ๊ฐ ๋ฐ๋ก webdriver.io์ ๋์ดํธ์์น ๊ทธ๋ฆฌ๊ณ ์ต๊ทค๋ฌ ํ๋ก์ ํธ๋ฅผ ์ํ ํ๋กํธ๋ํฐ๋ค.
์ด๋ค ๋๊ตฌ๋ ์น๋๋ผ์ด๋ฒ API๋ฅผ ์ฌ์ฉํ ๋ ์๊ธฐ๋ ๋ค์ํ ํจํด์ ์ถ์ํํ API์ ์ ํ์ค ์๊ฐ ๋ฑ์ ์ ๊ณตํด ์ ๋ ๋์ 2.0 ๋ณด๋ ๋ ํธ๋ฆฌํ๊ณ ๋ค์ํ ๊ฒฝํ์ ์ ๊ณตํ๋ค.
๋์ดํธ์์น
๋์ดํธ์์น๋ ๋ ธ๋ ๊ธฐ๋ฐ์ E2E ํ ์คํธ ํ๋ ์์ํฌ๋ค. ์ ๋ ๋์ ์น๋๋ผ์ด๋ฒ๋ฅผ ์ค๊ฐํ์ฌ ๊ฐ์ข ๋ธ๋ผ์ฐ์ ๋ฅผ ์กฐ์ํ๊ณ ๋์์ด ๊ธฐ๋ํ ๊ฒ๊ณผ ์ผ์นํ๋์ง ํ ์คํธํ๋๋ฐ ์ฌ์ฉํ๋ค. CSS ์ ๋ ํฐ๋ก ์๋ฆฌ๋จผํธ๋ฅผ ์ ๋ ํ ํ์ฌ ํ ์คํธ๋ฅผ ์์ฑํ ์ ์๋๋ก ํ๋ ๊ธฐ๋ฅ๊ณผ ์ ํ ์ค ์๊ฐ ๊ทธ๋ฆฌ๊ณ ๋จ์ํ๊ณ ๊ฐ๊ฒฐํ ๋ฌธ๋ฒ์ ์ ๊ณตํ๋ค. ๋ํ ํ ์คํธ ๋ฌ๋๋ฅผ ํฌํจํ๊ณ ์์ผ๋ฏ๋ก ๋ ์์ ์ผ๋ก ๊ทธ๋ฃนํํ ํ ์คํธ๋ฅผ ํ๋ฒ์ ์คํํ ์ ์์ผ๋ฉฐ ์ง์์ ์ธ ํตํฉ์ ํ์ดํ ๋ผ์ธ๊ณผ ํฉ์น ์ ์๋ค๋ ํน์ง์ ๊ฐ์ง๊ณ ์๋ค.
๋์ดํธ์์น๋ฅผ ์๊ฒ ๋๊ฑด ๋๋ณด๋ค ๋จผ์ E2E ํ ์คํธ๋ฅผ ๋ฆฌ์์นํ๊ณ ๊ด๋ จ ๋๊ตฌ๋ฅผ ์ฐพ๊ณ ์๋ ํ๋ฏผ์ดํ(๊ฐ๋ฐ์ ๊น์ฝ๋ฉ, ๋ธ๋ก๊ทธ) ๋๋ถ์ด์๋ค. ๋ฏธ๋ฆฌ ์ฝ์ง์ ํ๊ณ ๊ณ์ จ๊ธฐ ๋๋ฌธ์ ๋ค๋ฅธ ๋๊ตฌ๋ฅผ ์ ํํ๊ธฐ ๋ณด๋ค ๊ฐ์ด ์ฝ์งํ๋ ํธ์ด ๊ณ ๋ฏผํ ์๊ฐ๋ ์ ์ด์ ํฐ ๊ณ ๋ฏผ ์์ด ์ฌ์ฉํ๋ค.
์ค์นํ๊ธฐ
๋์ดํธ์์น ์ค์น๋ ๊ฐ๋ฐ์ ๊ฐ์ด๋ Getting Started ์ ์ ์ ์ค๋ช ๋ผ ์๋ค. ์ด ๋ฌธ์์๋ ๊ฐ๋จํ๊ฒ ์์ฝํด ์ค์น ๊ณผ์ ์ ์ค๋ช ํ๋ค. ์ฐ์ NPM์ ์ด์ฉํด ์ค์นํ๋ค.
$ npm install --save-dev nightwatch
์น๋๋ผ์ด๋ฒ๋ก ๋ธ๋ผ์ฐ์ ์ ํต์ ํ๊ธฐ ์ํด์๋ ์ ๋ ๋์ ์๋ฒ๋ฅผ ์คํ์์ผ์ผํ๋ค. ์ ๋ ๋์ ์๋ฒ ๋ค์ด๋ก๋ ์ฌ์ดํธ์์ ํ์ผ์ ๋ค์ด ๋ฐ๊ณ ์๋์ ๊ฐ์ด ์๋ฒ๋ฅผ ์คํํ๋ค. ์ด ๊ธ์ ์์ฑํ๋ ํ์ฌ ๊ธฐ์ค ๊ฐ์ฅ ์ต์ ๋ฒ์ ์ 2.53.0 ์ด๋ค.
ํ๋ก์ ํธ ๋๋ ํฐ๋ฆฌ์์ nightwatch.json์ ์์ฑํ๊ณ ๋ค์๊ณผ ๊ฐ์ด ์์ฑํ๋ค. ์ต์ ์ ์์ธํ ์ค๋ช ์ ๊ฐ๋ฐ์ ๊ฐ์ด๋ Configuration ์ ์ ์ฐธ๊ณ ํ๋ค.
{ "src_folders" : ["tests"], // ํ ์คํธํ ๋๋ ํฐ๋ฆฌ, ๋ฐฐ์ด๋ก ์ง์ "output_folder" : "tests/reports", // JUnit XML ๋ฆฌํฌํธ ํ์ผ์ด ์ ์ฅ๋ ์์น "custom_commands_path" : "", // ๋ถ๋ฌ์ฌ ์ปค์คํ ์ปค๋งจ๋๊ฐ ์๋ ์์น "custom_assertions_path" : "", // ๋ถ๋ฌ์ฌ ์ปค์คํ ์ด์ฐํธ๊ฐ ์๋ ์์น "page_objects_path" : "", // ๋ถ๋ฌ์ฌ ํ์ด์ง ๊ฐ์ฒด๊ฐ ์๋ ์์น "globals_path" : "", // ๋ถ๋ฌ์ฌ ์ธ๋ถ ๊ธ๋ก๋ฒ ๋ชจ๋์ด ์๋ ์์น "selenium" : { // ์ ๋ ๋์ ์๋ฒ ํ๊ฒฝ ์ค์ "start_process" : true, // ํ ์คํธ ์์์ ์ ๋ ๋์ ํ๋ก์ธ์ค๋ฅผ ์๋์ผ๋ก ์คํํ ๊ฒ ์ธ์ง ์ฌ๋ถ "server_path" : "./selenium-server-standalone-2.53.0.jar", // ์ ๋ ๋์ ์๋ฒ jar ํ์ผ์ ๊ฒฝ๋ก, start_process๊ฐ false๋ฉด ์ง์ ํ์ง ์์๋ ๋๋ค. "log_path" : "tests/logs", // ์ ๋ ๋์์ output.log ํ์ผ์ด ์ ์ฅ๋ ๊ฒฝ๋ก "host" : "127.0.0.1", // ์ ๋ ๋์ ์๋ฒ์ listen ip "port" : 4444, // ์ ๋ ๋์ ์๋ฒ์ listen port "cli_args" : { // ์ ๋ ๋์ ํ๋ก์ธ์ค๋ก ๋๊ฒจ์ง cli ์ธ์ ๋ชฉ๋ก "webdriver.chrome.driver" : "", "webdriver.ie.driver" : "" } }, "test_settings" : { // ํ ์คํธ ๋ธ๋ผ์ฐ์ ๋ณ ํ๊ฒฝ ์ค์ "default" : { // ๋ชจ๋ ๋ธ๋ผ์ฐ์ ์ ์ ์ฉ ๋ ๊ณตํต ์ค์ "launch_url" : "http://localhost", "selenium_port" : 4444, "selenium_host" : "localhost", "silent": true, // ์ ๋ ๋์์ ๋ก๊ทธ๋ฅผ ์จ๊ธธ์ง ์ฌ๋ถ "screenshots": { // ํ ์คํธ๊ฐ ์คํจ ํ์ ๋ ์ดฌ์ ๋ ์คํฌ๋ฆฐ์ท ์ค์ "enabled" : true, "on_failure" : true, "on_error" : false, "path" : "tests/screenshots" }, "desiredCapabilities": { // ์ ๋ ๋์ ์น๋๋ผ์ด๋ฒ๋ก ์ ๋ฌํ ๋ธ๋ผ์ฐ์ ์ด๋ฆ๊ณผ ๊ธฐ๋ฅ ์ง์ "browserName": "firefox", "javascriptEnabled": true, "acceptSslCerts": true } } } }
tests ๋๋ ํฐ๋ฆฌ ํ์์ demo.js๋ฅผ ์์ฑํ๊ณ ๊ฐ๋จํ ํ ์คํธ ์ฝ๋๋ฅผ ํ๋ค.
module.exports = { '์ฌ์ฉ์๋ ๊ฒ์์ด๋ฅผ ์ ๋ ฅ ํ ๊ฒ์์ด๊ฐ ํฌํจ๋ ์๋ ์์ฑ ๋ฆฌ์คํธ๋ฅผ ๋ณผ ์ ์๋ค.' : function (browser) { browser .url('http://www.google.com') .waitForElementVisible('body', 1000) .setValue('input[type=text]', 'nightwatch') .pause(1000) .assert.containsText('#sbtc', 'nightwatch') .end(); } };
์ด์ด์ ์๋ ๋ช ๋ น์ด๋ก ๊ฐ๋จํ E2E ํ ์คํธ๋ฅผ ์คํํ ์ ์๋ค.
$ ./node_modules/nightwatch/bin/nightwatch
ํ์ง๋ง ํ์ฌ ํ์ด์ดํญ์ค ๋ฒ์ 47์ ๋ฌธ์ ๊ฐ ์์ด ํ ์คํธ๊ฐ ์คํ๋์ง ์์๊ฒ์ด๋ค. ํ์ด์ดํญ์ค์์ ํ ์คํธ ํ๊ณ ์ถ๋ค๋ฉด ์์ ๋ฒ์ (Install an older version of Firefox)์ผ๋ก ๋ค์ด๊ทธ๋ ์ด๋ ํ๊ฑฐ๋ GeckoDriver๋ฅผ ์ฌ์ฉํด์ผํ๋ค(Setting up the Marionette executable). ์ฌ๊ธฐ์์๋ GeckoDriver๋ฅผ ์ด์ฉํ๋ ๋ฐฉ๋ฒ์ ์๊ฐ(OSX ๊ธฐ์ค)ํ๊ฒ ๋ค.
๋จผ์ mozilla/geckodriver์์ GeckoDriver๋ฅผ ๋ค์ด๋ก๋ํ๋ค.
$ cd ~/Downloads $ wget https://github.com/mozilla/geckodriver/releases/download/v0.8.0/geckodriver-0.8.0-OSX.gz
๋ค์ด๋ก๋ํ ํ์ผ์ ์์ถ ํด์ ํ๊ณ ์ ๋นํ ์์น๋ก ์ฎ๊ธด ํ ์คํ๊ฐ๋ฅํ ํ์ผ๋ก ๋ณ๊ฒฝํ๋ค.
$ gunzip geckodriver-0.8.0-OSX.gz $ mkdir executable && mv geckodriver-0.8.0-OSX executable/wires $ chmod 755 executable/wires
์ด์ .bash_profile(๋๋ .zshrc)์์ PATH๋ฅผ ์ง์ ํ๋ค.
$ vim ~/.zshrc GECKO_DRIVER=$HOME/Downloads/executable export PATH=$HOME/bin:/usr/local/bin:/usr/local/sbin:$GECKO_DRIVER:$PATH # rcํ์ผ์ ๋ค์ ๋ถ๋ฌ์จ๋ค. $ source ~/.zshrc
๋ง์ง๋ง์ผ๋ก nightwatch.jsonํ์ผ์์ desiredCapabilities ์์ฑ์ ๋ค์๊ณผ ๊ฐ์ด ๋ณ๊ฒฝํ๋ค.
"desiredCapabilities": { "browserName": "firefox", "marionette": true, // ์ถ๊ฐ "javascriptEnabled": true, "acceptSslCerts": true }
์ด์ ๋ค์ ์คํํด๋ณด๋ฉด ํ์ด์ดํญ์ค ๋ธ๋ผ์ฐ์ ์์ ์ ์์ ์ผ๋ก ํ ์คํธ๊ฐ ์งํ๋ ๊ฒ์ด๋ค.
<๊ทธ๋ฆผ 3 ๋ฐ๋ชจ ํ ์คํธ ์คํ ๊ฒฐ๊ณผ>
์ฌ๋ฌ ๋ธ๋ผ์ฐ์ ์์ ๋์์ ํ ์คํธํ๊ธฐ
ํ์ฌ ์์ฑํ ์ค์ ํ์ผ๋ก ๋์ดํธ์์น๋ฅผ ์คํํ๋ฉด ํ์ด์ดํญ์ค์์๋ง ํ ์คํธ๊ฐ ์งํ๋๋ค. ์ด๋ฒ์ ํฌ๋กฌ ๋ธ๋ผ์ฐ์ ์์๋ ํ ์คํธ๊ฐ ์งํ๋๋๋ก ์ค์ ์ ๋ณ๊ฒฝํ๊ฒ ๋ค. ํฌ๋กฌ ๋ธ๋ผ์ฐ์ ๋ ์ ๋ ๋์๊ณผ ํต์ ํ ์น๋๋ผ์ด๋ฒ๋ฅผ ๋ณ๋๋ก ์ค์นํด์ผํ๋๋ฐ ์น๋๋ผ์ด๋ฒ ๋งค๋์ ๋ฅผ ์ฌ์ฉํ๋ฉด ์ฝ๊ฒ ์ค์นํ ์ ์๋ค. ์๋ ๋ช ๋ น์ด๋ก ์น๋๋ผ์ด๋ฒ ๋งค๋์ ๋ฅผ ์ค์นํ๋ค.
$ npm install --save-dev webdriver-manager # ํฌ๋กฌ ์น๋๋ผ์ด๋ฒ์ ์ ์ ์์ ๋ค์ด๋ก๋ ๋ฐ์๋ ์ ๋ ๋์ ์๋ฒ๊ฐ ํจ๊ป ์ค์น๋๋ค. $ ./node_modules/.bin/webdriver-manager update # ๋๋ ์๋ ๋ช ๋ น์ด ์ฒ๋ผ ์ธ์๋ฅผ ์ ๋ฌํด ๋ณ๋๋ก ์ค์นํ ์๋ ์๋ค. # ./node_modules/.bin/webdriver-manager update --chrome
์ด์ nightwatch.json์ ์ ๋ ๋์ ์๋ฒ ๊ฒฝ๋ก์ ํฌ๋กฌ ์น๋๋ผ์ด๋ฒ ์๋ฒ ๊ฒฝ๋ก๋ฅผ ์์ ํ๋ค.
"selenium": { "start_process": true, "server_path": "./selenium-server-standalone-2.53.0.jar", "log_path": "tests/logs", "host": "127.0.0.1", "port": 4444, "cli_args": { "webdriver.chrome.driver" : "node_modules/webdriver-manager/selenium/chromedriver_2.21", // ์ถ๊ฐ "webdriver.ie.driver": "" } },
๋ค์์ผ๋ก default ์์ฑ์ ์์ฑํ๋ ํ์ด์ดํญ์ค ๋ธ๋ผ์ฐ์ ์ค์ ์ test_settings ์์ฑ ํ์๋ก ์ฎ๊ธฐ๊ณ ํฌ๋กฌ ๋ธ๋ผ์ฐ์ ์ค์ ๋ ํจ๊ป ์ถ๊ฐ ์์ฑํ๋ค.
{ // ... ์๋ต ... "test_settings": { "default": { "launch_url": "http://localhost", "selenium_port": 4444, "selenium_host": "localhost", "silent": true, "screenshots": { "enabled" : true, "on_failure" : true, "on_error" : false, "path" : "tests/screenshots" } }, "firefox": { "desiredCapabilities": { "browserName": "firefox", "marionette": true, "javascriptEnabled": true, "acceptSslCerts": true } }, "chrome": { "desiredCapabilities": { "browserName": "chrome", "javascriptEnabled": true, "acceptSslCerts": true } } } }
์ด์ ์๋ ๋ช ๋ น์ด๋ก ์คํํ๋ฉด ๋ ๋ธ๋ผ์ฐ์ ์์ ๋์์ ํ ์คํธ๊ฐ ์คํ๋๋ค.
$ ./node_modules/nightwatch/bin/nightwatch --env firefox,chrome
์ฌํ๋ฆฌ ๋ธ๋ผ์ฐ์ ์์ ํ ์คํธํ๊ณ ์ ํ๋ค๋ฉด ์ฌํ๋ฆฌ ์น๋๋ผ์ด๋ฒ๋ฅผ ํ์ฅ ๊ธฐ๋ฅ์ผ๋ก ์ค์นํด์ผํ๋ค. ์์ธํ ๋ด์ฉ์ ๋์ดํธ์์น ์์น์ Running tests in Safari ๋ฌธ์๋ฅผ ์ฐธ๊ณ ํ๋ค.
<๊ทธ๋ฆผ 4 ์ฌํ๋ฆฌ์ ์น๋๋ผ์ด๋ฒ ํ์ฅํ๋ก๊ทธ๋จ>
๋ชจ์นด ์ฌ์ฉํ๊ธฐ
์ด๋ฒ์ ํ ์คํธ ์ฝ๋๋ฅผ ๋ชจ์นด ๊ธฐ๋ฐ์ผ๋ก ์์ฑํ ์ ์๋ ํ๊ฒฝ์ ๋ง๋ค์ด๋ณด๊ฒ ๋ค. ๋์ดํธ์์น๋ ์ด์ฐํธ๋ก ์ฑ ์ด(chai)๋ฅผ ๋ด์ฅํ๊ณ ์์ง๋ง ๋ชจ์นด๋ ๋ณ๋๋ก ์ค์ ํด ์ฌ์ฉํด์ผํ๋ค. ๋ชจ์นด๋ฅผ ์ค์ ํ๋ ์์ธํ ๋ด์ฉ์ ๊ฐ๋ฐ์ ๊ฐ์ด๋ Using Mocha ์ ์ ์ฐธ๊ณ ํ๋ค. ๋ชจ์นด๋ฅผ ๊ตณ์ด ์ฌ์ฉํ๋ ค๋ ์ด์ ๋ JUnit XML๋ก ๋ฆฌํฌํ ํ๋ ๊ธฐ๋ณธ ๋ฌ๋์๋ ๋ฌ๋ฆฌ ๋ค์ํ๊ณ ๋ณด๊ธฐ ์ฌ์ด ๋ฆฌํฌํ ์ ์ง์ํ๊ธฐ ๋๋ฌธ์ด๋ค.
๋จผ์ nightwatch.json ํ์ผ์ ๋ค์๊ณผ ๊ฐ์ด test_runner ์์ฑ์ ์ถ๊ฐํ๋ค. ์ต์ ์ ๊ดํ ์์ธํ ์ค๋ช ์ ๋ชจ์นด ์ํค์ Set options ์ ์ ์ฐธ๊ณ ํ๋ค.
{ "test_runner" : { "type" : "mocha", "options" : { "ui": "bdd", "reporter": "spec" } }, // ... ์๋ต ... }
ํ ์คํธ ์ฝ๋๋ฅผ ๋ชจ์นด ๊ธฐ๋ฐ์ผ๋ก ์ฌ์์ฑํ๋ค.
describe('๊ตฌ๊ธ ๋ฉ์ธ ํ์ด์ง', function() { before(function(client, done) { done(); }); after(function(client, done) { done(); }); describe('#์ฌ์ฉ์๋ ๊ฒ์ํ ์ ์๋ค.', function() { it('์ฌ์ฉ์๋ ๊ฒ์์ด๋ฅผ ์ ๋ ฅ ํ ์๋ ์์ฑ๋ ๋ฆฌ์คํธ๋ฅผ ๋ณผ ์ ์๋ค.', function(client, done) { client .url('http://www.google.com') .waitForElementVisible('body', 1000) .setValue('input[type=text]', 'nightwatch') .pause(1000) .assert.containsText('#sbtc', 'nightwatch') .end(done); }); }); });
๋ค์ ์คํํด ๋ณด๋ฉด ๋ชจ์นด ๊ธฐ๋ฐ์ผ๋ก ํ ์คํธ ์ฝ๋๊ฐ ๋์ํ๋ ๊ฒ์ ๋ณผ ์ ์๋ค.
<๊ทธ๋ฆผ 5 ๋ชจ์นด ํ ์คํธ ์คํ ๊ฒฐ๊ณผ>
๋ธ๋ผ์ฐ์ ์คํ
ํฌ๋ก์ค ๋ธ๋ผ์ฐ์ง ํ ์คํธ๋ฅผ ํ ์ ์๋๋ก ํด์ฃผ๋ ์น ์๋น์ค์ธ ๋ธ๋ผ์ฐ์ ์คํ์ ๋ค์ํ ํ๋ซํผ๊ณผ ์น ๋ธ๋ผ์ฐ์ ๋ฅผ ์ง์ํ๋ค. ๋ํ, ์ ๋ ๋์ ์๋ฒ๋ ์ ๊ณตํ๊ณ ์๋๋ฐ ์ด๋ฅผ ์ด์ฉํ๋ฉด ๋์ดํธ์์น์ ์ฐ๋ํด ํ ์คํธ๋ฅผ ์๋ํํ ์ ์๋ค.
๋จผ์ browserstack.json ํ์ผ์ ์์ฑํ๋ค.
{ // ... ์๋ต ... "selenium": { "start_process": false }, "test_settings": { "default" : { "launch_url" : "http://hub.browserstack.com", "selenium_host" : "hub.browserstack.com", "selenium_port" : 80, "silent" : true, "screenshots" : { "enabled" : true, "on_failure" : true, "on_error" : false, "path" : "tests/screenshots" }, "desiredCapabilities": { "platform": "xp", "browserName": "firefox", "javascriptEnabled": true, "acceptSslCerts": true, "browserstack.user" : "user_id", // ๋ธ๋ผ์ฐ์ ์คํ ์์ด๋ "browserstack.key" : "user_key" // ๋ธ๋ผ์ฐ์ ์คํ ํค } } } }
platform ์์ฑ์ XP๋ฅผ browserName ์์ฑ์ ํ์ด์ดํญ์ค๋ฅผ ์ง์ ํ๊ณ ๋ก์ปฌ ํ๊ฒฝ์์ ์ ๋ ๋์ ์๋ฒ๋ฅผ ์คํ์ํฌ ํ์๊ฐ ์๊ธฐ ๋๋ฌธ์ start_process์ false๋ก ์ง์ ํ๋ค. ์ด์ ๋ธ๋ผ์ฐ์ ์คํ์ ์๋์ฐ์ฆ XP ํ๊ฒฝ์ ํ์ด์ดํญ์ค ๋ธ๋ผ์ฐ์ ์์ ํ ์คํธ๋ฅผ ์งํํ ๊ฒ์ด๋ค. ๋ธ๋ผ์ฐ์ ์คํ์์ ์ง์ํ๋ ํ๋ซํผ๊ณผ ๋ธ๋ผ์ฐ์ ๋ ๊ณต์ ํํ์ด์ง์ Capabilities ํ์ด์ง๋ฅผ ์ฐธ๊ณ ํ๋ฉด ์ ์ ์๋ค.
์๋ ๋ช ๋ น์ด๋ฅผ ์ฐธ๊ณ ํด ์คํํด๋ณธ๋ค.
$ ./node_modules/nightwatch/bin/nightwatch --config browserstack.json
๋ค์ํ ํ๋ซํผ๊ณผ ๋ธ๋ผ์ฐ์ ์์ E2E ํ ์คํธ๋ฅผ ํ ์ ์๋ค๋ ์ ์ ํฐ ์ฅ์ ์ด์ง๋ง ํต์ ์ด๋ ํ ์คํธ๋ฅผ ๊ตฌ๋ํ๋ ์๋๊ฐ ์์ฃผ ๋๋ฆฌ๋ค. ๋ฐ๋ผ์ ํ ์คํธ ๋ฐฐ์น ํน์ ์ ๊ธฐ ๋ฐฐํฌ ์ ์๋ง ์ฌ์ฉํ๊ธฐ ์ ํฉํด ๋ณด์ธ๋ค.
์น์คํฐ ๋๋ฒ๊น
์น์คํฐ์์ ๋ ธ๋ ๋๋ฒ๊น ๋๊ตฌ๋ฅผ ์ฌ์ฉํด ๋์ดํธ์์น๋ฅผ ๋๋ฒ๊น ํ ์ ์๋ค. ์์ธํ ๋ด์ฉ์ Debugging Nightwatch tests in WebStorm์ ์ฐธ๊ณ ํ๋ค. ๋ค๋ง, ํ์ดํ๋ผ์ธ ๋ฐฉ์์ด๋ค ๋ณด๋ ๋ธ๋ ์ดํฌ ํฌ์ธํธ๋ฅผ ํ์ฉํ ๋๋ฒ๊น ์ด ๋ค์ ๋ฌด์๋ฏธํ ๋๋์ ์๋ค.
๋์ผ๋ก
์ฌ๊ธฐ๊น์ง ๋ค์ํ ์ฌ์ ์ง์์ ์ค๋ช ํ๊ณ ๋์ดํธ์์น์ ๊ดํด์ ์ดํดํด๋ดค๋ค. E2E ํ ์คํธ ํน์ฑ ์ ํ๋ก์ ํธ ์ ์ฅ์์ ํ ์คํธ๋ฅผ ์์ฑํ๊ณ ์ ์งํ๊ธฐ ๋ณด๋จ ๋ณ๋์ E2E ํ ์คํธ ์ ์ฅ์๋ฅผ ๋ง๋ค์ด ํ ์คํธ๋ฅผ ์์ฑํ๊ณ ์ ์งํ๋๊ฒ ๋ ํจ์จ์ ์ด์ง ์์๊น ์๊ฐํ๋ค. ๋, ๋์ดํธ์์น์๋ ํ์ด์ง ์ค๋ธ์ ํธ, ์ปค์คํ ์ปค๋งจ๋ ๋ฑ ํ ์คํธ๋ฅผ ์์ฑํ ๋ ์ ์ฉํ ๊ฐ๋ ์ ์ ๊ณตํ๋ค. ์ด ๋ ๊ฐ๋ ์ ์ ์ ํ ์ ์ฌ์ฉํ๋ฉด ์๊ฐ๋ณด๋ค ๋ ๊ด๋ฆฌํ๊ธฐ ์ฌ์ด ํ ์คํธ ์ฝ๋๋ฅผ ์์ฑํ ์ ์๋ค.
์์์ ์งํํ ์ค์น ๋ฐ ์ค์ ๊ณผ์ ์ UYEONG/hello-nightwatch์ ์ฌ๋ ค๋์์ผ๋ ์ฐธ๊ณ ํ๊ธธ ๋ฐ๋๋ค.
์ฐธ๊ณ
http://docs.seleniumhq.org/about/history.jsp
http://google-opensource.blogspot.kr/2009/05/introducing-webdriver.html
http://www.infoq.com/news/2011/07/Selenium-2
https://seleniumhq.wordpress.com/2011/07/08/selenium-2-0/
http://www.slideshare.net/sethmcl/join-the-darkside-nightwatchjs
https://github.com/SeleniumHQ/selenium/issues/2110
http://blog.trident-qa.com/2013/05/so-many-seleniums(์ผ๋ณธ์ด)
https://app.codegrid.net/entry/selenium-1(์ผ๋ณธ์ด)
http://pydiary.bitbucket.org/blog/html/2015/08/28/test.html(์ผ๋ณธ์ด)
http://blog.mmmcorp.co.jp/blog/2015/09/24/use-nightwatch/(์ผ๋ณธ์ด)
http://www.infoq.com/jp/news/2014/03/nightwatch(์ผ๋ณธ์ด)
http://qiita.com/yssg/items/a054d67bc7c7fc39b276(์ผ๋ณธ์ด)













