๋ณธ๋ฌธ์œผ๋กœ ๊ฑด๋„ˆ๋›ฐ๊ธฐ

๐Ÿญ ํด๋ฆฐ ์ฝ”๋“œ

P.154 ๋‹จ์œ„ ํ…Œ์ŠคํŠธโ€‹

TDD ๋ฒ•์น™ ์„ธ ๊ฐ€์ง€โ€‹

  • ์ฒซ์งธ ๋ฒ•์น™: ์‹คํŒจํ•˜๋Š” ๋‹จ์œ„ ํ…Œ์ŠคํŠธ๋ฅผ ์ž‘์„ฑํ•  ๋•Œ๊นŒ์ง€ ์‹ค์ œ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•˜์ง€ ์•Š๋Š”๋‹ค.
  • ๋‘˜์งธ ๋ฒ•์น™: ์ปดํŒŒ์ผ์€ ์‹คํŒจํ•˜์ง€ ์•Š์œผ๋ฉด์„œ ์‹คํ–‰์ด ์‹คํŒจํ•˜๋Š” ์ •๋„๋กœ๋งŒ ๋‹จ์œ„ ํ…Œ์ŠคํŠธ๋ฅผ ์ž‘์„ฑํ•œ๋‹ค.
  • ์…‹์งธ ๋ฒ•์น™: ํ˜„์žฌ ์‹คํŒจํ•˜๋Š” ํ…Œ์ŠคํŠธ๋ฅผ ํ†ต๊ณผํ•  ์ •๋„๋กœ๋งŒ ์‹ค์ œ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•œ๋‹ค.

์œ„ ์„ธ ๊ฐ€์ง€ ๊ทœ์น™์„ ๋”ฐ๋ฅด๋ฉด ๊ฐœ๋ฐœ๊ณผ ํ…Œ์ŠคํŠธ๊ฐ€ ๋Œ€๋žต 30์ดˆ ์ฃผ๊ธฐ๋กœ ๋ฌถ์ธ๋‹ค. ํ…Œ์ŠคํŠธ ์ฝ”๋“œ์™€ ์‹ค์ œ ์ฝ”๋“œ๊ฐ€ ํ•จ๊ป˜ ๋‚˜์˜ฌ๋ฟ๋”๋Ÿฌ ํ…Œ์ŠคํŠธ ์ฝ”๋“œ๊ฐ€ ์‹ค์ œ ์ฝ”๋“œ๋ณด๋‹ค ๋ถˆ๊ณผ ๋ช‡ ์ดˆ ์ „์— ๋‚˜์˜จ๋‹ค.
์ด๋ ‡๊ฒŒ ์ผํ•˜๋ฉด ์‹ค์ œ ์ฝ”๋“œ๋ฅผ ์‚ฌ์‹ค์ƒ ์ „๋ถ€ ํ…Œ์ŠคํŠธํ•˜๋Š” ํ…Œ์ŠคํŠธ ์ผ€์ด์Šค๊ฐ€ ๋‚˜์˜จ๋‹ค. ํ•˜์ง€๋งŒ ์‹ค์ œ ์ฝ”๋“œ์™€ ๋งž๋จน์„ ์ •๋„๋กœ ๋ฐฉ๋Œ€ํ•œ ํ…Œ์ŠคํŠธ ์ฝ”๋“œ๋Š” ์‹ฌ๊ฐํ•œ ๊ด€๋ฆฌ ๋ฌธ์ œ๋ฅผ ์œ ๋ฐœํ•˜๊ธฐ๋„ ํ•œ๋‹ค.

๊นจ๋—ํ•œ ํ…Œ์ŠคํŠธ ์ฝ”๋“œ ์œ ์ง€ํ•˜๊ธฐโ€‹

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

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

ํ•˜์ง€๋งŒ ํ…Œ์ŠคํŠธ ์ผ€์ด์‚ญ ์žˆ๋‹ค๋ฉด ๊ณตํฌ๋Š” ์‚ฌ์‹ค์ƒ ์‚ฌ๋ผ์ง„๋‹ค. ํ…Œ์ŠคํŠธ ์ปค๋ฒ„๋ฆฌ์ง€๊ฐ€ ๋†’์„์ˆ˜๋ก ๊ณตํฌ๊ฐ€ ์ค„์–ด๋“ ๋‹ค. ์•„ํ‚คํ…์ฒ˜๊ฐ€ ๋ถ€์‹คํ•œ ์ฝ”๋“œ๋‚˜ ์„ค๊ณ„๊ฐ€ ๋ชจํ˜ธํ•˜๊ณ  ์—‰๋ง์ธ ์ฝ”๋“œ๋ผ๋„ ๋ณ„๋‹ค๋ฅธ ์šฐ๋ ค ์—†์ด ๋ณ€๊ฒฝํ•  ์ˆ˜ ์žˆ๋‹ค.

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

๊นจ๋—ํ•œ ํ…Œ์ŠคํŠธ ์ฝ”๋“œโ€‹

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

public void testGetPageHierarchyAsXml() throws Exception {
makePages("PageOne", "PageOne.ChildOne", "PageTwo");

submitRequest("root", "type:pages");

assertResponseIsXML();
assertResponseContains(
"<name>PageOne</name>", "<name>PageTwo</name>", "<name>ChildOne</name>"
);
}

public void testSymbolicLinksAreNotInXmlPageHierarchy() throws Exception {
WikiPage page = makePage("PageOne");
makePages("PageOne.ChildOne", "PageTwo");

addLinkTo(page, "PageTwo", "SymPage");

submitRequest("root", "type:pages");

assertResponseIsXML();
assertResponseContains(
"<name>PageOne</name>", "<name>PageTwo</name>", "<name>ChildOne</name>"
);
assertResponseDoesNotContain("SymPage");
}

public void testGetDataAsXml() throws Exception {
makePageWithContent("TestPageOne", "test page");

submitRequest("TestPageOne", "type:data");

assertResponseIsXML();
assertResponseContains("test page", "<Test");
}

๊ฐ ํ…Œ์ŠคํŠธ๋Š” ๋ช…ํ™•ํžˆ ์„ธ ๋ถ€๋ถ„์œผ๋กœ ๋‚˜๋ˆ ์ง„๋‹ค. ์ฒซ ๋ถ€๋ถ„์€ ํ…Œ์ŠคํŠธ ์ž๋ฃŒ๋ฅผ ๋งŒ๋“ ๋‹ค. ๋‘ ๋ฒˆ์งธ ๋ถ€๋ถ„์€ ํ…Œ์ŠคํŠธ ์ž๋ฃŒ๋ฅผ ์กฐ์ž‘ํ•˜๋ฉฐ, ์„ธ ๋ฒˆ์งธ ๋ถ€๋ถ„์€ ์กฐ์ž‘ํ•œ ๊ฒฐ๊ณผ๊ฐ€ ์˜ฌ๋ฐ”๋ฅธ์ง€ ํ™•์ธํ•œ๋‹ค.

์œ„ ํ…Œ์ŠคํŠธ ์ฝ”๋“œ๋Š” ๋„๋ฉ”์ธ์— ํŠนํ™”๋œ ์–ธ์–ด(DSL)๋กœ ํ…Œ์ŠคํŠธ ์ฝ”๋“œ๋ฅผ ๊ตฌํ˜„ํ•˜๋Š” ๊ธฐ๋ฒ•์„ ๋ณด์—ฌ์ค€๋‹ค. ํ…Œ์ŠคํŠธ๋ฅผ ๊ตฌํ˜„ํ•˜๋Š” ๋‹น์‚ฌ์ž์™€ ๋‚˜์ค‘์— ํ…Œ์ŠคํŠธ๋ฅผ ์ฝ์–ด๋ณผ ๋…์ž๋ฅผ ๋„์™€์ฃผ๋Š” ํ…Œ์ŠคํŠธ ์–ธ์–ด๋‹ค.

ํ…Œ์ŠคํŠธ API์ฝ”๋“œ์— ์ ์šฉํ•˜๋Š” ํ‘œ์ค€์€ ์‹ค์ œ ์ฝ”๋“œ์— ์ ์šฉํ•˜๋Š” ํ‘œ์ค€๊ณผ ํ™•์‹คํžˆ ๋‹ค๋ฅด๋‹ค. ๋‹จ์ˆœํ•˜๊ณ , ๊ฐ„๊ฒฐํ•˜๊ณ , ํ‘œํ˜„๋ ฅ์ด ํ’๋ถ€ํ•ด์•ผ ํ•˜์ง€๋งŒ, ์‹ค์ œ ์ฝ”๋“œ๋งŒํผ ํšจ์œจ์ ์ผ ํ•„์š”๋Š” ์—†๋‹ค. ์‹ค์ œ ํ™˜๊ฒฝ์ด ์•„๋‹ˆ๋ผ ํ…Œ์ŠคํŠธ ํ™˜๊ฒฝ์—์„œ ๋Œ์•„๊ฐ€๋Š” ์ฝ”๋“œ์ด๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค. ์‹ค์ œ ํ™˜๊ฒฝ๊ณผ ํ…Œ์ŠคํŠธ ํ™˜๊ฒฝ์€ ์š”๊ตฌ์‚ฌํ•ญ์ด ํŒ์ดํ•˜๊ฒŒ ๋‹ค๋ฅด๋‹ค.

ํ…Œ์ŠคํŠธ ๋‹น assert ํ•˜๋‚˜โ€‹

assert ๋ฌธ์ด ๋‹จ ํ•˜๋‚˜์ธ ํ•จ์ˆ˜๋Š” ๊ฒฐ๋ก ์ด ํ•˜๋‚˜๋ผ์„œ ์ฝ”๋“œ๋ฅผ ์ดํ•ดํ•˜๊ธฐ ์‰ฝ๊ณ  ๋น ๋ฅด๋‹ค. ํ•˜์ง€๋งŒ ์œ„ ์˜ˆ์‹œ ์ฝ”๋“œ์—์„œ "์ถœ๋ ฅ์ด XML์ด๋‹ค"๋ผ๋Š” assert ๋ฌธ๊ณผ "ํŠน์ • ๋ฌธ์ž์—ด์„ ํฌํ•จํ•œ๋‹ค"๋Š” assert ๋ฌธ์„ ํ•˜๋‚˜๋กœ ๋ณ‘ํ•ฉํ•˜๋Š” ๋ฐฉ์‹์ด ๋ถˆํ•ฉ๋ฆฌํ•ด ๋ณด์ธ๋‹ค. ๋‹ค์Œ ์˜ˆ์‹œ ์ฝ”๋“œ์—์„œ ๋ณด๋“ฏ์ด ํ…Œ์ŠคํŠธ๋ฅผ ๋‘ ๊ฐœ๋กœ ์ชผ๊ฐœ ๊ฐ์ž๊ฐ€ assert๋ฅผ ์ˆ˜ํ–‰ํ•˜๋ฉด ๋œ๋‹ค.

public void testGetPageHierarchyAsXml() throws Exception {
givenPages("PageOne", "PageOne.ChildOne", "PageTwo");

whenRequestIsIssued("root", "type:pages");

thenResponseShouldBeXML();
}

public void testGetPageHierarchyHasRightTags() throws Exception {
givenPages("PageOne", "PageOne.ChildOne", "PageTwo");

whenRequestIsIssued("root", "type:pages");

assertResponseContains(
"<name>PageOne</name>", "<name>PageTwo</name>", "<name>ChildOne</name>"
);
}

์œ„์—์„œ ํ•จ์ˆ˜ ์ด๋ฆ„์„ ๋ฐ”๊ฟ” given-when-then์ด๋ผ๋Š” ๊ด€๋ ˆ๋ฅผ ์‚ฌ์šฉํ–ˆ๋‹ค๋Š” ์‚ฌ์‹ค์— ์ฃผ๋ชฉํ•œ๋‹ค. ๊ทธ๋Ÿฌ๋ฉด ํ…Œ์ŠคํŠธ ์ฝ”๋“œ๋ฅผ ์ฝ๊ธฐ๊ฐ€ ์‰ฌ์›Œ์ง„๋‹ค. ๋ถˆํ–‰ํ•˜๊ฒŒ๋„, ์œ„์—์„œ ๋ณด๋“ฏ์ด, ํ…Œ์ŠคํŠธ๋ฅผ ๋ถ„๋ฆฌํ•˜๋ฉด ์ค‘๋ณต๋˜๋Š” ์ฝ”๋“œ๊ฐ€ ๋งŽ์•„์ง„๋‹ค. TEMPLATE METHOD ํŒจํ„ด์„ ์‚ฌ์šฉํ•˜๋ฉด ์ค‘๋ณต์„ ์ œ๊ฑฐํ•  ์ˆ˜ ์žˆ๋‹ค. given/when ๋ถ€๋ถ„์„ ๋ถ€๋ชจ ํฌ๋ž˜์Šค์— ๋‘๊ณ  then ๋ถ€๋ถ„์„ ์ž์‹ ํด๋ž˜์Šค์— ๋‘๋ฉด ๋œ๋‹ค. ์•„๋‹ˆ๋ฉด ์™„์ „ํžˆ ๋…์ž์ ์ธ ํ…Œ์ŠคํŠธ ํด๋ž˜์Šค๋ฅผ ๋งŒ๋“ค์–ด @Before ํ•จ์ˆ˜์— given/when ๋ถ€๋ถ„์„ ๋„ฃ๊ณ  @Test ํ•จ์ˆ˜์— then ๋ถ€๋ถ„์„ ๋„ฃ์–ด๋„ ๋œ๋‹ค. ํ•˜์ง€๋งŒ ๋ชจ๋‘๊ฐ€ ๋ฐฐ๋ณด๋‹ค ๋ฐฐ๊ผฝ์ด ๋” ํฌ๋‹ค. ์ด๊ฒƒ์ €๊ฒƒ ๊ฐ์•ˆํ•ด ๋ณด๋ฉด ๊ฒฐ๊ตญ ์ด์ „์˜ ์˜ˆ์‹œ ์ฝ”๋“œ์ฒ˜๋Ÿผ assert ๋ฌธ์„ ์—ฌ๋Ÿฟ ์‚ฌ์šฉํ•˜๋Š” ํŽธ์ด ์ข‹๋‹ค๊ณ  ์ƒ๊ฐํ•œ๋‹ค. ๋‹จ, assert ๋ฌธ ๊ฐœ์ˆ˜๋Š” ์ตœ๋Œ€ํ•œ ์ค„์—ฌ์•ผ ์ข‹๋‹ค.

์–ด์ฉŒ๋ฉด "ํ…Œ์ŠคํŠธ ํ•จ์ˆ˜๋งˆ๋‹ค ํ•œ ๊ฐœ๋…๋งŒ ํ…Œ์ŠคํŠธํ•˜๋ผ"๋Š” ๊ทœ์น™์ด ๋” ๋‚ซ๊ฒ ๋‹ค. ์ด๊ฒƒ์ €๊ฒƒ ์žก๋‹คํ•œ ๊ฐœ๋…์„ ์—ฐ์†์ ์œผ๋กœ ํ…Œ์ŠคํŠธํ•˜๋Š” ๊ธด ํ•จ์ˆ˜๋Š” ํ”ผํ•œ๋‹ค. ์ฆ‰, assert ๋ฌธ์ด ์—ฌ๋Ÿฟ์ด๋ผ๋Š” ์‚ฌ์‹ค์ด ๋ฌธ์ œ๊ฐ€ ์•„๋‹ˆ๋‹ค. ํ•œ ํ…Œ์ŠคํŠธ ํ•จ์ˆ˜์—์„œ ์—ฌ๋Ÿฌ ๊ฐœ๋…์„ ํ…Œ์ŠคํŠธํ•œ๋‹ค๋Š” ์‚ฌ์‹ค์ด ๋ฌธ์ œ๋‹ค. ๊ทธ๋Ÿฌ๋ฏ€๋กœ ๊ฐ€์žฅ ์ข‹์€ ๊ทœ์น™์€ "๊ฐœ๋… ๋‹น assert ๋ฌธ ์ˆ˜๋ฅผ ์ตœ์†Œ๋กœ ์ค„์—ฌ๋ผ"์™€ "ํ…Œ์ŠคํŠธ ํ•จ์ˆ˜ ํ•˜๋‚˜๋Š” ๊ฐœ๋… ํ•˜๋‚˜๋งŒ ํ…Œ์ŠคํŠธํ•˜๋ผ"๋ผ ํ•˜๊ฒ ๋‹ค.

F.I.R.S.Tโ€‹

๊บ ๋—ํ•œ ํ…Œ์ŠคํŠธ๋Š” ๋‹ค์Œ ๋‹ค์„ฏ ๊ฐ€์ง€ ๊ทœ์น™์„ ๋”ฐ๋ฅด๋Š”๋ฐ, ๊ฐ ๊ทœ์น™์—์„œ ์ฒซ ๊ธ€์ž๋ฅผ ๋”ฐ์˜ค๋ฉด FIRST๊ฐ€ ๋œ๋‹ค.

  • ๋น ๋ฅด๊ฒŒ(Fast): ํ…Œ์ŠคํŠธ๋Š” ๋นจ๋ผ์•ผ ํ•œ๋‹ค. ํ…Œ์ŠคํŠธ๋Š” ๋นจ๋ฆฌ ๋Œ์•„์•ผ ํ•œ๋‹ค๋Š” ๋ง์ด๋‹ค. ํ…Œ์ŠคํŠธ๊ฐ€ ๋Š๋ฆฌ๋ฉด ์ž์ฃผ ๋Œ๋ฆด ์—„๋‘๋ฅผ ๋ชป ๋‚ธ๋‹ค. ์ž์ฃผ ๋Œ๋ฆฌ์ง€ ์•Š์œผ๋ฉด ์ดˆ๋ฐ˜์— ๋ฌธ์ œ๋ฅผ ์ฐพ์•„๋‚ด ๊ณ ์น˜์ง€ ๋ชปํ•œ๋‹ค. ์ฝ”๋“œ๋ฅผ ๋งˆ์Œ๊ป ์ •๋ฆฌํ•˜์ง€๋„ ๋ชปํ•œ๋‹ค. ๊ฒฐ๊ตญ ์ฝ”๋“œ ํ’ˆ์งˆ์ด ๋ง๊ฐ€์ง€๊ธฐ ์‹œ์ž‘ํ•œ๋‹ค.
  • ๋…๋ฆฝ์ ์œผ๋กœ(Independent): ๊ฐ ํ…Œ์ŠคํŠธ๋Š” ์„œ๋กœ ์˜์กดํ•˜๋ฉด ์•ˆ ๋œ๋‹ค. ํ•œ ํ…Œ์ŠคํŠธ๊ฐ€ ๋‹ค์Œ ํ…Œ์ŠคํŠธ๊ฐ€ ์‹คํ–‰๋  ํ™˜๊ฒฝ์„ ์ค€๋น„ํ•ด์„œ๋Š” ์•ˆ ๋œ๋‹ค. ๊ฐ ํ…Œ์ŠคํŠธ๋Š” ๋…๋ฆฝ์ ์œผ๋กœ ๊ทธ๋ฆฌ๊ณ  ์–ด๋–ค ์ˆœ์„œ๋กœ ์‹คํ–‰ํ•ด๋„ ๊ดœ์ฐฎ์•„์•ผ ํ•œ๋‹ค. ํ…Œ์ŠคํŠธ๊ฐ€ ์˜์กดํ•˜๋ฉด ํ•˜๋‚˜๊ฐ€ ์‹คํŒจํ•  ๋•Œ ๋‚˜๋จธ์ง€๋„ ์ž‡๋‹ฌ์•„ ์‹คํŒจํ•˜๋ฏ€๋กœ ์›์ธ์„ ์ง„๋‹จํ•˜๊ธฐ ์–ด๋ ค์›Œ์ง€๋ฉฐ ํ›„๋ฐ˜ ํ…Œ์ŠคํŠธ๊ฐ€ ์ฐพ์•„๋‚ด์•ผ ํ•  ๊ฒฐํ•จ์ด ์ˆจ๊ฒจ์ง„๋‹ค.
  • ๋ฐ˜๋ณต๊ฐ€๋Šฅํ•˜๊ฒŒ(Repeatable): ํ…Œ์ŠคํŠธ๋Š” ์–ด๋–ค ํ™˜๊ฒฝ์—์„œ๋„ ๋ฐ˜๋ณต ๊ฐ€๋Šฅํ•ด์•ผ ํ•œ๋‹ค. ์‹ค์ œ ํ™˜๊ฒฝ, QA ํ™˜๊ฒฝ, ๋ฒ„์Šค๋ฅผ ํƒ€๊ณ  ์ง‘์œผ๋กœ ๊ฐ€๋Š” ๊ธธ์— ์‚ฌ์šฉํ•˜๋Š” (๋„คํŠธ์›Œํฌ์— ์—ฐ๊ฒฐ๋˜์ง€ ์•Š์€) ๋…ธํŠธ๋ถ ํ™˜๊ฒฝ์—์„œ๋„ ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ์–ด์•ผ ํ•œ๋‹ค. ํ…Œ์ŠคํŠน ๋Œ์•„๊ฐ€์ง€ ์•Š๋Š” ํ™˜๊ฒฝ์ด ํ•˜๋‚˜๋ผ๋„ ์žˆ๋‹ค๋ฉด ํ…Œ์ŠคํŠธ๊ฐ€ ์‹คํŒจํ•œ ์ด์œ ๋ฅผ ๋‘˜๋Ÿฌ๋Œˆ ๋ณ€๋ช…์ด ์ƒ๊ธด๋‹ค. ๊ฒŒ๋‹ค๊ฐ€ ํ™˜๊ฒฝ์ด ์ง€์›๋˜์ง€ ์•Š๊ธฐ์— ํ…Œ์ŠคํŠธ๋ฅผ ์ˆ˜ํ–‰ํ•˜์ง€ ๋ชปํ•˜๋Š” ์ƒํ™ฉ์— ์ง๋ฉดํ•œ๋‹ค.
  • ์ž๊ฐ€๊ฒ€์ฆํ•˜๋Š”(Self-Validating): ํ…Œ์ŠคํŠธ๋Š” ๋ถ€์šธ(bool)๊ฐ’์œผ๋กœ ๊ฒฐ๊ณผ๋ฅผ ๋‚ด์•ผ ํ•œ๋‹ค. ์„ฑ๊ณต ์•„๋‹ˆ๋ฉด ์‹คํŒจ๋‹ค. ํ†ต๊ณผ ์—ฌ๋ถ€๋ฅผ ์•Œ๋ ค๊ณ  ๋กœ๊ทธ ํŒŒ์ผ์„ ์ฝ๊ฒŒ ๋งŒ๋“ค์–ด์„œ๋Š” ์•ˆ ๋œ๋‹ค. ํ…Œ์ŠคํŠธ๊ฐ€ ์Šค์Šค๋กœ ์„ฑ๊ณต๊ณผ ์‹คํŒจ๋ฅผ ๊ฐ€๋Š ํ•˜์ง€ ์•Š๋Š”๋‹ค๋ฉด ํŒ๋‹จ์€ ์ฃผ๊ด€์ ์ด ๋˜๋ฉฐ ์ง€๋ฃจํ•œ ์ˆ˜์ž‘์—… ํ‰๊ฐ€๊ฐ€ ํ•„์š”ํ•˜๊ฒŒ ๋œ๋‹ค.
  • ์ ์‹œ์—(Timely): ํ…Œ์ŠคํŠธ๋Š” ์ ์‹œ์— ์ž‘์„ฑํ•ด์•ผ ํ•œ๋‹ค. ๋‹จ์œ„ ํ…Œ์ŠคํŠธ๋Š” ํ…Œ์ŠคํŠธํ•˜๋ ค๋Š” ์‹ค์ œ ์ฝ”๋“œ๋ฅผ ๊ตฌํ˜„ํ•˜๊ธฐ ์ง์ „์— ๊ตฌํ˜„ํ•œ๋‹ค. ์‹ค์ œ ์ฝ”๋“œ๋ฅผ ๊ตฌํ˜„ํ•œ ๋‹ค์Œ์— ํ…Œ์ŠคํŠธ ์ฝ”๋“œ๋ฅผ ๋งŒ๋“ค๋ฉด ์‹ค์ œ ์ฝ”๋“œ๊ฐ€ ํ…Œ์ŠคํŠธํ•˜๊ธฐ ์–ด๋ ต๋‹ค๋Š” ์‚ฌ์‹ค์„ ๋ฐœ๊ฒฌํ• ์ง€๋„ ๋ชจ๋ฅธ๋‹ค. ์–ด๋–ค ์‹ค์ œ ์ฝ”๋“œ๋Š” ํ…Œ์ŠคํŠธํ•˜๊ธฐ ๋„ˆ๋ฌด ์–ด๋ ต๋‹ค๊ณ  ํŒ๋ช…๋‚ ์ง€ ๋ชจ๋ฅธ๋‹ค. ํ…Œ์ŠคํŠธ๊ฐ€ ๋ถˆ๊ฐ€๋Šฅํ•˜๋„๋ก ์‹ค์ œ ์ฝ”๋“œ๋ฅผ ์„ค๊ณ„ํ• ์ง€๋„ ๋ชจ๋ฅธ๋‹ค.

ํ…Œ์ŠคํŠธ ์ฝ”๋“œ๋Š” ์ง€์†์ ์œผ๋กœ ๊นจ๋—ํ•˜๊ฒŒ ๊ด€๋ฆฌํ•˜์ž. ํ‘œํ˜„๋ ฅ์„ ๋†’์ด๊ณ  ๊ฐ„๊ฒฐํ•˜๊ฒŒ ์ •๋ฆฌํ•˜์ž. ๊ทธ๋Ÿฌ๋ฉด ๊ทธ๋งŒํผ ํ…Œ์ŠคํŠธ ์ฝ”๋“œ๋ฅผ ์งœ๊ธฐ๊ฐ€ ์‰ฌ์›Œ์ง„๋‹ค.
ํ…Œ์ŠคํŠธ API๋ฅผ ๊ตฌํ˜„ํ•ด ๋„๋ฉ”์ธ ํŠนํ™” ์–ธ์–ด(DSL)๋ฅผ ๋งŒ๋“ค์ž. ๊ทธ๋Ÿฌ๋ฉด ๊ทธ๋งŒํผ ํ…Œ์ŠคํŠธ ์ฝ”๋“œ๋ฅผ ์งœ๊ธฐ๊ฐ€ ์‰ฌ์›Œ์ง„๋‹ค. ํ…Œ์ŠคํŠธ ์ฝ”๋“œ๋ฅผ ๊นจ๋—ํ•˜๊ฒŒ ์œ ์ง€ํ•˜์ž.