Skip to content

Latest commit

ย 

History

History
288 lines (211 loc) ยท 17.8 KB

File metadata and controls

288 lines (211 loc) ยท 17.8 KB

9์žฅ. ๋‹จ์œ„ ํ…Œ์ŠคํŠธ

๊ทœ์น™

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

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

์œ„ ์„ธ๊ฐ€์ง€ ๊ทœ์น™์„ ๋”ฐ๋ฅด๋ฉด์„œ ์ผํ•˜๋ฉด ์‹ค์ œ ์ฝ”๋“œ๋ฅผ ์‚ฌ์‹ค์ƒ ์ „๋ถ€ ํ…Œ์ŠคํŠธํ•˜๋Š” ํ…Œ์ŠคํŠธ ์ผ€์ด์Šค๊ฐ€ ๋‚˜์˜จ๋‹ค. ํ•˜์ง€๋งŒ ์‹ค์ œ ์ฝ”๋“œ์™€ ๋งž๋จน์„ ์ •๋„๋กœ ๋ฐฉ๋Œ€ํ•œ ํ…Œ์ŠคํŠธ ์ฝ”๋“œ๋Š” ์‹ฌ๊ฐํ•œ ๊ด€๋ฆฌ ๋ฌธ์ œ๋ฅผ ์œ ๋ฐœํ•˜๊ธฐ๋„ ํ•œ๋‹ค.

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

์‹ค์ œ ์ฝ”๋“œ๊ฐ€ ์ง„ํ™”ํ•˜๋ฉด ํ…Œ์ŠคํŠธ ์ฝ”๋“œ๋„ ๋ณ€ํ•ด์•ผ ํ•œ๋‹ค. ๊ทธ๋Ÿฐ๋ฐ ํ…Œ์ŠคํŠธ ์ฝ”๋“œ๊ฐ€ ์ง€์ €๋ถ„ํ• ์ˆ˜๋ก ๋ณ€๊ฒฝํ•˜๊ธฐ ์–ด๋ ค์›Œ์ง„๋‹ค. ์‹ค์ œ ์ฝ”๋“œ๋ฅผ ๋ณ€๊ฒฝํ•ด ๊ธฐ์กด ํ…Œ์ŠคํŠธ ์ผ€์ด์Šค๊ฐ€ ์‹คํŒจํ•˜๊ธฐ ์‹œ์ž‘ํ•˜๋ฉด, ์ง€์ €๋ถ„ํ•œ ์ฝ”๋“œ๋กœ ์ธํ•ด, ์‹คํŒจํ•˜๋Š” ํ…Œ์ŠคํŠธ ์ผ€์ด์Šค๋ฅผ ์ ์  ๋” ํ†ต๊ณผ์‹œํ‚ค๊ธฐ ์–ด๋ ค์›Œ์ง„๋‹ค. ๊ทธ๋ž˜์„œ ํ…Œ์ŠคํŠธ ์ฝ”๋“œ๋Š” ๊ณ„์†ํ•ด์„œ ๋Š˜์–ด๋‚˜๋Š” ๋ถ€๋‹ด์ด ๋˜๋ฒ„๋ฆฐ๋‹ค.

ํ…Œ์ŠคํŠธ ์ฝ”๋“œ๋Š” ์‹ค์ œ ์ฝ”๋“œ ๋ชป์ง€ ์•Š๊ฒŒ ์ค‘์š”ํ•˜๋‹ค. ํ…Œ์ŠคํŠธ ์ฝ”๋“œ๋Š” ์‚ฌ๊ณ ์™€ ์„ค๊ณ„์™€ ์ฃผ์˜๊ฐ€ ํ•„์š”ํ•˜๋‹ค. ์‹ค์ œ ์ฝ”๋“œ ๋ชป์ง€ ์•Š๊ฒŒ ๊นจ๋—ํ•˜๊ฒŒ ์งœ์•ผ ํ•œ๋‹ค.

ํ…Œ์ŠคํŠธ๋Š” ์œ ์—ฐ์„ฑ, ์œ ์ง€๋ณด์ˆ˜์„ฑ, ์žฌ์‚ฌ์šฉ์„ฑ์„ ์ œ๊ณตํ•œ๋‹ค

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

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

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

๋”ฐ๋ผ์„œ ํ…Œ์ŠคํŠธ ์ฝ”๋“œ๊ฐ€ ์ง€์ €๋ถ„ํ•˜๋ฉด ์ฝ”๋“œ๋ฅผ ๋ณ€๊ฒฝํ•˜๋Š” ๋Šฅ๋ ฅ์ด ๋–จ์–ด์ง€๋ฉฐ ์ฝ”๋“œ ๊ตฌ์กฐ๋ฅผ ๊ฐœ์„ ํ•˜๋Š” ๋Šฅ๋ ฅ๋„ ๋–จ์–ด์ง„๋‹ค.

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

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

๋‹ค์Œ ์ฝ”๋“œ๋ฅผ ๋ณด์ž. FitNess์—์„œ ๊ฐ€์ ธ์˜จ ์ฝ”๋“œ๋‹ค. ์•„๋ž˜ ํ…Œ์ŠคํŠธ ์ผ€์ด์Šค ์„ธ ๊ฐœ๋Š” ์ดํ•ดํ•˜๊ธฐ ์–ด๋ ต๊ธฐ์— ๊ฐœ์„ ํ•  ์—ฌ์ง€๊ฐ€ ์ถฉ๋ถ„ํ•˜๋‹ค.

  1. addPage์™€ assertSubString์„ ๋ถ€๋ฅด๋А๋ผ ์ค‘๋ณต๋˜๋Š” ์ฝ”๋“œ๊ฐ€ ๋งค์šฐ ๋งŽ๋‹ค. ์ž์งˆ๊ตฌ๋ ˆํ•œ ์‚ฌํ•ญ์ด ๋„ˆ๋ฌด ๋งŽ์•„ ํ…Œ์ŠคํŠธ ์ฝ”๋“œ์˜ ํ‘œํ˜„๋ ฅ์ด ๋–จ์–ด์ง„๋‹ค.
  2. PathParser ํ˜ธ์ถœ์„ ์‚ดํŽด๋ณด๋ฉด, PathParser๋Š” ๋ฌธ์ž์—ด์„ pagePath ์ธ์Šคํ„ด์Šค๋กœ ๋ณ€ํ™˜ํ•œ๋‹ค. pagePath๋Š” ์›น ๋กœ๋ด‡crawler์ด ์‚ฌ์šฉํ•˜๋Š” ๊ฐ์ฒด๋‹ค. ์ด ์ฝ”๋“œ๋Š” ํ…Œ์ŠคํŠธ์™€ ๋ฌด๊ด€ํ•˜๋ฉฐ ํ…Œ์ŠคํŠธ ์ฝ”๋“œ์˜ ์˜๋„๋งŒ ํ๋ฆฐ๋‹ค.
  3. responder ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•˜๋Š” ์ฝ”๋“œ์™€ response๋ฅผ ์ˆ˜์ง‘ํ•ด ๋ณ€ํ™˜ํ•˜๋Š” ์ฝ”๋“œ ์—ญ์‹œ ์žก์Œ์— ๋ถˆ๊ณผํ•˜๋‹ค.
  4. resource์™€ ์ธ์ˆ˜์—์„œ ์š”์ฒญ URL์„ ๋งŒ๋“œ๋Š” ์–ด์„คํ”ˆ ์ฝ”๋“œ๋„ ๋ณด์ธ๋‹ค.
  5. ์ฝ๋Š” ์‚ฌ๋žŒ์„ ๊ณ ๋ คํ•˜์ง€ ์•Š๋Š”๋‹ค.
public func testGetPageHieratchyAsXml() throws -> Void {
    crawler.addPage(root, PathParser.parse("PageOne"))
    crawler.addPage(root, PathParser.parse("PageOne.ChildOne"))
    crawler.addPage(root, PathParser.parse("PageTwo"))

    request.setResource("root")
    request.addInput("type", "pages")
    var responder: Responder = SerializedPageResponder()
    var response: SimpleResponse = responder.makeResponse(FitNesseContext(root), request) as? SimpleResponse
    var xml: String = response.getContent()

    assertEquals("text/xml", response.getContentType())
    assertSubString("<name>PageOne</name>", xml)
    assertSubString("<name>PageTwo</name>", xml)
    assertSubString("<name>ChildOne</name>", xml)
}

public func testGetPageHieratchyAsXmlDoesntContainSymbolicLinks() throws -> Void {
    var pageOne: WikiPage = crawler.addPage(root, PathParser.parse("PageOne"))
    crawler.addPage(root, PathParser.parse("PageOne.ChildOne"))
    crawler.addPage(root, PathParser.parse("PageTwo"))

    var data: PageData = pageOne.getData()
    var properties: WikiPageProperties = data.getProperties()
    var symLinks: WikiPageProperty = properties.set(SymbolicPage.PROPERTY_NAME)
    symLinks.set("SymPage", "PageTwo")
    pageOne.commit(data)

    request.setResource("root")
    request.addInput("type", "pages")
    var responder: Responder = SerializedPageResponder()
    var response: SimpleResponse = responder.makeResponse(FitNesseContext(root), request) as? SimpleResponse
    var xml: String = response.getContent()

    assertEquals("text/xml", response.getContentType())
    assertSubString("<name>PageOne</name>", xml)
    assertSubString("<name>PageTwo</name>", xml)
    assertSubString("<name>ChildOne</name>", xml)
    assertNotSubString("SymPage", xml)
}

public func testGetDataAsHtml() throws -> Void {
    crawler.addPage(root, PathParser.parse("PageOne"), "test page")

    request.setResouce("TestPageOne")
    request.addInput("type", "data")
    var responder: Responder = SerializedPageResponder()
    var response: SimpleResponse = responder.makeResponse(FitNesseContext(root), request) as? SimpleResponse
    var xml: String = response.getContent()

    assertEquals("text/xml", response.getContentType())
    assertSubString("test page", xml)
    assertSubString("<Test", xml)
}

๋‹ค์Œ ์ฝ”๋“œ๋ฅผ ์‚ดํŽด๋ณด์ž. ์œ„ ์ฝ”๋“œ๋ฅผ ๊ฐœ์„ ํ•œ ์ฝ”๋“œ๋กœ, ์ •ํ™•ํžˆ ๋™์ผํ•œ ํ…Œ์ŠคํŠธ๋ฅผ ์ˆ˜ํ–‰ํ•œ๋‹ค. ํ•˜์ง€๋งŒ ์ข€ ๋” ๊นจ๋—ํ•˜๊ณ  ์ข€ ๋” ์ดํ•ดํ•˜๊ธฐ ์‰ฝ๋‹ค.

public func testGetPageHieratchyAsXml() throws -> Void {
    makePages("PageOne", "PageOne.ChildOne", "PageTwo")

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

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

public func testGetPageHieratchyAsXmlDoesntContainSymbolicLinks() throws -> Void {
    var page: WikiPage = 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 func testGetDataAsHtml() throws -> Void {
    makePageWithContent("TestPageOne", "test page")

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

    assertResponseIsXml()
    assertResponseContains("test page", "<Test")
}

๊ฐ ํ…Œ์ŠคํŠธ๋Š” ๋ช…ํ™•ํžˆ ์„ธ ๋ถ€๋ถ„์œผ๋กœ ๋‚˜๋ˆ ์ง„๋‹ค.

  1. ํ…Œ์ŠคํŠธ ์ž๋ฃŒ๋ฅผ ๋งŒ๋“ ๋‹ค.
  2. ํ…Œ์ŠคํŠธ ์ž๋ฃŒ๋ฅผ ์กฐ์ž‘ํ•œ๋‹ค.
  3. ์กฐ์ž‘ํ•œ ๊ฒฐ๊ณผ๊ฐ€ ์˜ฌ๋ฐ”๋ฅธ์ง€ ํ™•์ธํ•œ๋‹ค.

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

๋„๋ฉ”์ธ์— ํŠนํ™”๋œ ํ…Œ์ŠคํŠธ ์–ธ์–ด

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

์ˆ™๋ จ๋œ ๊ฐœ๋ฐœ์ž๋ผ๋ฉด ์ž๊ธฐ ์ฝ”๋“œ๋ฅผ ์ข€ ๋” ๊ฐ„๊ฒฐํ•˜๊ณ  ํ‘œํ˜„๋ ฅ์ด ํ’๋ถ€ํ•œ ์ฝ”๋“œ๋กœ ๋ฆฌํŒฉํ„ฐ๋งํ•ด์•ผ ๋งˆ๋•…ํ•˜๋‹ค.

์ด์ค‘ ํ‘œ์ค€

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

@Test
public func turnOnLoTempAlarmAtThreashold() throws -> Void {
    hw.setTemp(WAY_TOO_COLD); 
    controller.tic(); 
    assertTrue(hw.heaterState());   
    assertTrue(hw.blowerState()); 
    assertFalse(hw.coolerState()); 
    assertFalse(hw.hiTempAlarm());       
    assertTrue(hw.loTempAlarm());
}

์œ„ ์ฝ”๋“œ๋ฅผ ์ฝ์œผ๋ฉด ์ฝ”๋“œ์—์„œ ์ ๊ฒ€ํ•˜๋Š” ์ƒํƒœ ์ด๋ฆ„๊ณผ ์ƒํƒœ ๊ฐ’์„ ํ™•์ธํ•˜๋А๋ผ ๋ˆˆ๊ธธ์ด ์ด๋ฆฌ์ €๋ฆฌ ํฉ์–ด์ง„๋‹ค. heaterState๋ผ๋Š” ์ƒํƒœ๋ฅผ ๋ณด๊ณ ์„œ๋Š” ์™ผ์ชฝ์œผ๋กœ ๋ˆˆ๊ธธ์„ ๋Œ๋ ค assertTrue๋ฅผ ์ฝ๋Š”๋‹ค. ํ…Œ์ŠคํŠธ ์ฝ”๋“œ๋ฅผ ์ฝ๊ธฐ๊ฐ€ ์–ด๋ ต๋‹ค.

@Test
public func turnOnLoTempAlarmAtThreashold() throws -> Void {
    wayTooCold()
    assertEquals("HBchL", hw.getState())
}

tic ํ•จ์ˆ˜๋Š” wayTooCold๋ผ๋Š” ํ•จ์ˆ˜๋ฅผ ๋งŒ๋“ค์–ด ์ˆจ๊ฒผ๋‹ค. assertEquals์— ๋“ค์–ด์žˆ๋Š” ์ด์ƒํ•œ ๋ฌธ์ž์—ด์— ์ฃผ๋ชฉํ•˜์ž. ๋Œ€๋ฌธ์ž๋Š” '์ผœ์งon'์ด๊ณ  ์†Œ๋ฌธ์ž๋Š” '๊บผ์งoff'์„ ๋œปํ•œ๋‹ค. ๋ฌธ์ž๋Š” ํ•ญ์ƒ {heater, blower, cooler, hi-temp-alarm, lo-temp-alarm} ์ˆœ์„œ๋‹ค.

๋น„๋ก ์œ„ ๋ฐฉ์‹์ด ๊ทธ๋ฆ‡๋œ ์ •๋ณด๋ฅผ ํ”ผํ•˜๋ผ๋Š” ๊ทœ์น™์˜ ์œ„๋ฐ˜์— ๊นŒ๊ฐ‘์ง€๋งŒ ์—ฌ๊ธฐ์„œ๋Š” ์ ์ ˆํ•ด๋ณด์ธ๋‹ค. ์ผ๋‹จ ์˜๋ฏธ๋งŒ ์•ˆ๋‹ค๋ฉด ๋ˆˆ๊ธธ์ด ๋ฌธ์ž์—ด์„ ๋”ฐ๋ผ ์›€์ง์ด๋ฉฐ ๊ฒฐ๊ณผ๋ฅผ ์žฌ๋นจ๋ฆฌ ํŒ๋‹จํ•œ๋‹ค.

public func getState() -> String {
    var state = ""
    state += heater ? "H" : "h"
    state += blower ? "B" : "b"
    state += cooler ? "C" : "c"
    state += hiTempAlarm ? "H" : "h"
    state += lotempAlarm ? "L" : "l"
    return state
}

์ฝ”๋“œ๊ฐ€ ๊ทธ๋ฆฌ ํšจ์œจ์ ์ด์ง€ ๋ชปํ•˜๋‹ค. (์ž๋ฐ”์—์„œ) ํšจ์œจ์„ ๋†’์ด๋ ค๋ฉด StringBuffer๊ฐ€ ๋” ์ ํ•ฉํ•˜๋‹ค. ์ด ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์€ ์‹ค์‹œ๊ฐ„ ์ž„๋ฒ ๋””๋“œ ์‹œ์Šคํ…œ์ด๋‹ค. ์ฆ‰, ์ปดํ“จํ„ฐ ์ž์›๊ณผ ๋ฉ”๋ชจ๋ฆฌ๊ฐ€ ์ œํ•œ์ ์ผ ๊ฐ€๋Šฅ์„ฑ์ด ๋†’๋‹ค. ํ•˜์ง€๋งŒ ํ…Œ์ŠคํŠธ ํ™˜๊ฒฝ์€ ์ž์›์ด ์ œํ•œ์ ์ผ ๊ฐ€๋Šฅ์„ฑ์ด ๋‚ฎ๋‹ค.

์ด๊ฒƒ์ด ์ด์ค‘ ํ‘œ์ค€์˜ ๋ณธ์งˆ์ด๋‹ค. ์‹ค์ œ ํ™˜๊ฒฝ์—์„œ๋Š” ์ ˆ๋Œ€๋กœ ์•ˆ ๋˜์ง€๋งŒ ํ…Œ์ŠคํŠธ ํ™˜๊ฒฝ์—์„œ๋Š” ์ „ํ˜€ ๋ฌธ์ œ์—†๋Š” ๋ฐฉ์‹์ด ์žˆ๋‹ค. ๋Œ€๊ฒŒ ๋ฉ”๋ชจ๋ฆฌ๋‚˜ CPU ํšจ์œจ๊ณผ ๊ด€๋ จ ์žˆ๋Š” ๊ฒฝ์šฐ๋‹ค. ์ฝ”๋“œ์˜ ๊นจ๋—ํ•จ๊ณผ๋Š” ์ฒ ์ €ํžˆ ๋ฌด๊ด€ํ•˜๋‹ค.

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

JUnit์œผ๋กœ ํ…Œ์ŠคํŠธ ์ฝ”๋“œ๋ฅผ ์งค ๋•Œ๋Š” ํ•จ์ˆ˜๋งˆ๋‹ค assert ๋ฌธ์„ ๋‹จ ํ•˜๋‚˜๋งŒ ์‚ฌ์šฉํ•ด์•ผ ํ•œ๋‹ค๊ณ  ์ฃผ์žฅํ•˜๋Š” ํ•™ํŒŒ๊ฐ€ ์žˆ๋‹ค. ๊ฐ€ํ˜นํ•œ ๊ทœ์น™์ด๋ผ ์—ฌ๊ธธ์ง€๋„ ๋ชจ๋ฅด์ง€๋งŒ, assert ๋ฌธ์ด ๋‹จ ํ•˜๋‚˜์ธ ํ•จ์ˆ˜๋Š” ๊ฒฐ๋ก ์ด ํ•˜๋‚˜๋ผ์„œ ์ฝ”๋“œ๋ฅผ ์ดํ•ดํ•˜๊ธฐ ์‰ฝ๊ณ  ๋น ๋ฅด๋‹ค.

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

public func testGetPageHierarchyAsXml() throws -> Void {
    givenPages("PageOne", "PageOne.ChildOne", "PageTwo")

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

    thenResponseShouldBeXML()
}

public func testGetPageHierarchyHasRightTags() throws -> Void {
    givenPages("PageOne", "PageOne.ChildOne", "PageTwo")

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

    thenResponseShouldContain("<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 ๋ฌธ ๊ฐœ์ˆ˜๋Š” ์ตœ๋Œ€ํ•œ ์ค„์—ฌ์•ผ ์ข‹๋‹ค๋Š” ์ƒ๊ฐ์ด๋‹ค.

ํ…Œ์ŠคํŠธ ๋‹น ๊ฐœ๋… ํ•˜๋‚˜

์–ด์ฉŒ๋ฉด "ํ…Œ์ŠคํŠธ ํ•จ์ˆ˜๋งˆ๋‹ค ํ•œ ๊ฐœ๋…๋งŒ ํ…Œ์ŠคํŠธํ•˜๋ผ"๋Š” ๊ทœ์น™์ด ๋” ๋‚ซ๊ฒŸ๋‹ค. ์ด๊ฒƒ์ €๊ฒƒ ์žก๋‹คํ•œ ๊ฐœ๋…์„ ์—ฐ์†์œผ๋กœ ํ…Œ์ŠคํŠธํ•˜๋Š” ๊น€ ํ•จ์ˆ˜๋Š” ํ”ผํ•œ๋‹ค.

// BAD
/**
 * addMonth() ๋ฉ”์„œ๋“œ๋ฅผ ํ…Œ์ŠคํŠธํ•˜๋Š” ์žฅํ™ฉํ•œ ์ฝ”๋“œ
 */
public func testAddMonths() {
    var d1: SerialDate = SerialDate.createInstance(31, 5, 2004);

    var d2: SerialDate = SerialDate.addMonths(1, d1); 
    assertEquals(30, d2.getDayOfMonth()); 
    assertEquals(6, d2.getMonth()); 
    assertEquals(2004, d2.getYYYY());

    var d3: SerialDate = SerialDate.addMonths(2, d1); 
    assertEquals(31, d3.getDayOfMonth()); 
    assertEquals(7, d3.getMonth()); 
    assertEquals(2004, d3.getYYYY());

    var d4: SerialDate = SerialDate.addMonths(1, SerialDate.addMonths(1, d1)); 
    assertEquals(30, d4.getDayOfMonth());
    assertEquals(7, d4.getMonth());
    assertEquals(2004, d4.getYYYY());
}

ํ…Œ์ŠคํŠธ ํ•จ์ˆ˜๋Š” ๊ฐ๊ฐ ๋‹ค์Œ ๊ธฐ๋Šฅ์„ ์ˆ˜ํ–‰ํ•œ๋‹ค.

  • (5์›”์ฒ˜๋Ÿผ) 31๋กœ ๋๋‚˜๋Š” ๋‹ฌ์˜ ๋งˆ์ง€๋ง‰ ๋‚ ์งœ๊ฐ€ ์ฃผ์–ด์ง€๋Š” ๊ฒฝ์šฐ
    1. (6์›”์ฒ˜๋Ÿผ) 30์ผ๋กœ ๋๋‚˜๋Š” ํ•œ ๋‹ฌ์„ ๋”ํ•˜๋ฉด ๋‚ ์งœ๋Š” 30์ผ์ด ๋˜์–ด์•ผ์ง€ 31์ผ์ด ๋˜์–ด์„œ๋Š” ์•ˆ ๋œ๋‹ค.
    2. ๋‘ ๋‹ฌ์„ ๋”ํ•˜๋ฉด ๊ทธ๋ฆฌ๊ณ  ๋‘ ๋ฒˆ์งธ ๋‹ฌ์ด 31๋กœ ๋๋‚˜๋ฉด ๋‚ ์งœ๋Š” 31์ผ์ด ๋˜์–ด์•ผ ํ•œ๋‹ค.
  • (6์›”์ฒ˜๋Ÿผ) 30์ผ๋กœ ๋๋‚˜๋Š” ๋‹ฌ์˜ ๋งˆ์ง€๋ง‰ ๋‚ ์งœ๊ฐ€ ์ฃผ์–ด์ง€๋Š” ๊ฒฝ์šฐ
    1. 31์ผ๋กœ ๋๋‚˜๋Š” ํ•œ ๋‹ฌ์„ ๋”ํ•˜๋ฉด ๋‚ ์งœ๋Š” 30์ผ์ด ๋˜์–ด์•ผ์ง€ 31์ผ์ด ๋˜๋ฉด ์•ˆ ๋œ๋‹ค.

์œ„ ์ฝ”๋“œ๋Š” ๊ฐ ์ ˆ์— assert ๋ฌธ์ด ์—ฌ๋Ÿฟ์ด๋ผ๋Š” ์‚ฌ์‹ค์ด ๋ฌธ์ œ๊ฐ€ ์•„๋‹ˆ๋‹ค. ํ•œ ํ…Œ์ŠคํŠธ ํ•จ์ˆ˜์—์„œ ์—ฌ๋Ÿฌ ๊ฐœ๋…์„ ํ…Œ์ŠคํŠธํ•œ๋‹ค๋Š” ์‚ฌ์‹ค์ด ๋ฌธ์ œ๋‹ค.

๊ฐ€์žฅ ์ข‹์€ ๊ทœ์น™์€ "๊ฐœ๋… ๋‹น assert ๋ฌธ ์ˆ˜๋ฅผ ์ตœ์†Œ๋กœ ์ค„์—ฌ๋ผ"์™€ "ํ…Œ์ŠคํŠธ ํ•จ์ˆ˜ ํ•˜๋‚˜๋Š” ๊ฐœ๋… ํ•˜๋‚˜๋งŒ ํ…Œ์ŠคํŠธํ•˜๋ผ"

F.I.R.S.T

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

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

๊ฒฐ๋ก 

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

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