๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ

Java/CleanCode

[CleanCode] 9์žฅ ๋‹จ์œ„ ํ…Œ์ŠคํŠธ

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

    ๐Ÿ’ป TDD(Test Driven Development)

    โ—ฝ ํ…Œ์ŠคํŠธ ์ฃผ๋„ ๊ฐœ๋ฐœ (์‹ค์ œ ์ฝ”๋“œ๋ฅผ ์งœ๊ธฐ ์ „์— ๋‹จ์œ„ ํ…Œ์ŠคํŠธ๋ถ€ํ„ฐ ์งœ๋ผ)
    โ—ฝ ์• ์ž์ผ๊ณผ TDD ๋•ํƒ์— ๋‹จ์œ„ ํ…Œ์ŠคํŠธ๋ฅผ ์ž๋™ํ™”ํ•˜๋Š” ํ”„๋กœ๊ทธ๋ž˜๋จธ๋“ค์ด ์ด๋ฏธ ๋งŽ์•„์กŒ์œผ๋ฉฐ ์ ์  ๋Š˜์–ด๋‚˜๋Š” ์ถ”์„ธ์ด๋‹ค.
       ๊ทธ๋Ÿฌ๋‚˜ ๋งŽ์€ ํ”„๋กœ๊ทธ๋ž˜๋จธ๋“ค์ด ์ œ๋Œ€๋กœ ๋œ ํ…Œ์ŠคํŠธ ์ผ€์ด์Šค๋ฅผ ์ž‘์„ฑํ•ด์•ผ ํ•œ๋‹ค๋Š” ์ข€ ๋” ์ค‘์š”ํ•œ ์‚ฌ์‹ค์„ ๋†“์ณ๋ฒ„๋ ธ๋‹ค. 

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

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

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

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

 

  • ํ…Œ์ŠคํŠธ๋Š” ์œ ์—ฐ์„ฑ, ์œ ์ง€๋ณด์ˆ˜์„ฑ, ์žฌ์‚ฌ์šฉ์„ฑ์„ ์ œ๊ณตํ•œ๋‹ค
    • ํ…Œ์ŠคํŠธ ์ฝ”๋“œ๋ฅผ ๊นจ๋—ํ•˜๊ฒŒ ์œ ์ง€ํ•˜์ง€ ์•Š์œผ๋ฉด ๊ฒฐ๊ตญ ์žƒ์–ด๋ฒ„๋ฆฐ๋‹ค.
      • ํ…Œ์ŠคํŠธ ์ผ€์ด์Šค๊ฐ€ ์—†์œผ๋ฉด ์‹ค์ œ ์ฝ”๋“œ๋ฅผ ์œ ์—ฐํ•˜๊ฒŒ ๋งŒ๋“œ๋Š” ๋ฒ„ํŒ€๋ชฉ๋„ ์‚ฌ๋ผ์ง„๋‹ค.
    • ์ฝ”๋“œ์˜ ์œ ์—ฐ์„ฑ, ์œ ์ง€๋ณด์ˆ˜์„ฑ, ์žฌ์‚ฌ์šฉ์„ฑ์„ ์ œ๊ณตํ•˜๋Š” ๋ฒ„ํŒ€๋ชฉ์ด ๋ฐ”๋กœ ๋‹จ์œ„ํ…Œ์ŠคํŠธ๋‹ค.
      • ํ…Œ์ŠคํŠธ ์ผ€์ด์Šค๊ฐ€ ์žˆ์œผ๋ฉด ๋ณ€๊ฒฝ์ด ๋‘๋ ต์ง€ ์•Š๋‹ค!
      • ํ…Œ์ŠคํŠธ ์ผ€์ด์Šค๊ฐ€ ์—†๋‹ค๋ฉด ๋ชจ๋“  ๋ณ€๊ฒฝ์ด ์ž ์ •์ ์ธ ๋ฒ„๊ทธ๋‹ค.
      • ์•„ํ‚คํ…์ฒ˜๊ฐ€ ์•„๋ฌด๋ฆฌ ์œ ์—ฐํ•˜๋”๋ผ๋„, ์„ค๊ณ„๋ฅผ ์•„๋ฌด๋ฆฌ ์ž˜ ๋‚˜๋ˆ ๋†จ๋”๋ผ๋„, ํ…Œ์ŠคํŠธ ์ผ€์ด์Šค๊ฐ€ ์—†์œผ๋ฉด ๊ฐœ๋ฐœ์ž๋Š” ๋ฒ„๊ทธ๊ฐ€ ๋‘๋ ค์›Œ ๋ณ€๊ฒฝ์„ ์ฃผ์ €ํ•œ๋‹ค.
    • ํ…Œ์ŠคํŠธ ์ปค๋ฒ„๋ฆฌ์ž๊ฐ€ ๋†’์„์ˆ˜๋ก ๊ณตํฌ๋Š” ์ค„์–ด๋“ ๋‹ค.
      • ์•„ํ‚คํ…์ฒ˜๊ฐ€ ๋ถ€์‹คํ•œ ์ฝ”๋“œ๋‚˜ ์„ค๊ณ„๊ฐ€ ๋ชจํ˜ธํ•˜๊ณ  ์—‰๋ง์ธ ์ฝ”๋“œ๋ผ๋„ ๋ณ„๋‹ค๋ฅธ ์šฐ๋ ค ์—†์ด ๋ณ€๊ฒฝํ•  ์ˆ˜ ์žˆ๋‹ค.
      • ์‹ค์ œ ์ฝ”๋“œ๋ฅผ ์ ๊ฒ€ํ•˜๋Š” ์ž๋™ํ™”๋œ ๋‹จ์œ„ ํ…Œ์ŠคํŠธ๋Š” ์„ค๊ณ„์™€ ์•„ํ‚คํ…์ฒ˜๋ฅผ ์ตœ๋Œ€ํ•œ ๊นจ๋—ํ•˜๊ฒŒ ๋ณด์กดํ•˜๋Š” ์—ด์‡ ๋‹ค.
      • ํ…Œ์ŠคํŠธ ์ผ€์ด์Šค๊ฐ€ ์žˆ์œผ๋ฉด ๋ณ€๊ฒฝ์ด ์‰ฌ์›Œ์ง€๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค. ๋”ฐ๋ผ์„œ ํ…Œ์ŠคํŠธ ์ฝ”๋“œ๊ฐ€ ์ง€์ €๋ถ„ํ•ด์ง€๋ฉด ์ฝ”๋“œ๋ฅผ ๋ณ€๊ฒฝํ•˜๋Š” ๋Šฅ๋ ฅ์ด ๋–จ์–ด์ง€๋ฉฐ ์ฝ”๋“œ ๊ตฌ์กฐ๋ฅผ ๊ฐœ์„ ํ•˜๋Š” ๋Šฅ๋ ฅ๋„ ๋–จ์–ด์ง„๋‹ค.
    • ๊ฒฐ๊ตญ ํ…Œ์ŠคํŠธ ์ฝ”๋“œ๋ฅผ ์žƒ์–ด๋ฒ„๋ฆฌ๊ณ  ์‹ค์ œ ์ฝ”๋“œ๋„ ๋ง๊ฐ€์ง„๋‹ค.
      • ํ…Œ์ŠคํŠธ ์ฝ”๋“œ๊ฐ€ ์ง€์ €๋ถ„ํ• ์ˆ˜๋ก ์‹ค์ œ ์ฝ”๋“œ๋„ ์ง€์ €๋ถ„ํ•ด์ง„๋‹ค.
  • ๊นจ๋—ํ•œ ํ…Œ์ŠคํŠธ ์ฝ”๋“œ
    • ๊นจ๋—ํ•œ ํ…Œ์ŠคํŠธ ์ฝ”๋“œ๋ฅผ ๋งŒ๋“ค๋ ค๋ฉด ์„ธ ๊ฐ€์ง€๊ฐ€ ํ•„์š”ํ•˜๋‹ค. ๊ฐ€๋…์„ฑ, ๊ฐ€๋…์„ฑ, ๊ฐ€๋…์„ฑ ์ด๋‹ค.
    • ํ…Œ์ŠคํŠธ ์ฝ”๋“œ์—์„œ ๊ฐ€๋…์„ฑ์„ ๋†’์ด๋ ค๋ฉด ๋ช…๋ฃŒ์„ฑ, ๋‹จ์ˆœ์„ฑ, ํ’๋ถ€ํ•œ ํ‘œํ˜„๋ ฅ์ด ํ•„์š”ํ•˜๋‹ค.
    • ํ…Œ์ŠคํŠธ ์ฝ”๋“œ๋Š” ์ตœ์†Œํ•œ์˜ ํ‘œํ˜„์œผ๋กœ ๋งŽ์€ ๊ฒƒ์„ ๋‚˜ํƒ€๋‚ด์•ผ ํ•œ๋‹ค.
    SerializedPageResponderTest.java
public void testGetPageHieratchyAsXml() throws Exception
{
    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");
    Responder responder = new SerializedPageResponder();
    SimpleResponse response = (SimpleResponse) responder.makeResponse(
        new FitNesseContext(root), request);

    String xml = response.getContext();

    assertEquals("test/xml", response.getContextType());
    assertSubString("<name>PageOne</name>", xml);
    assertSubString("<name>PageTwo</name>", xml);
    assertSubString("<name>ChildOne</name>", xml);
}

public void testGetPageHieratchyAsXmlDoesntContainSymbolicLinks() throws Exception {
    WikiPage pageOne = crawler.addPage(root, PathParser.parse("PageOne"));
    crawler.addPage(root, PathParser.parse("PageOne.ChildOne"));
    PageData data = pageOne.getData();
    WikiPageProperties properties = data.getProperties();
    WikiPageProperty symLinks = properties.set(SymbolicPage.PROPERTY_NAME);
    symLinks.set("SymPage", "PageTwo");
    pageOne.commit(data);

    request.setResource("root");
    request.addInput("type", "pages");
    Responder responder = new SerializedPageResponder();
    SimpleResponse response = (SimpleResponse) responder.makeResponse(new FitNesseContext(root), request);
    String xml = 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 void testGetDataAsHtml() throws Exception {
    crawler.addPage(root, PathParser.parse("TestPageOne", "test page");

    request.setREsource("TestPageOne");
    request.addInput("type", "data");
    Responder responder = new SerializedPageResponder();
    SimpleResponse response = (SimpleResponse) responder.makeResponse(new FitNesseContext(root), request);
    String xml = response.getContext();

    assertEquals("text/xml", response.getContextType());
    assertSubString("test page", xml);
    assertSubString("<Test", xml);
}
  • PathParser: ๋ฌธ์ž์—ด์„ pagePath ์ธ์Šคํ„ด์Šค๋กœ ๋ณ€ํ™˜. pagePath๋Š” ์›น ๋กœ๋ด‡(crawler)์ด ์‚ฌ์šฉํ•˜๋Š” ๊ฐ์ฒด
    • ํ…Œ์ŠคํŠธ์™€ ๋ฌด๊ด€ํ•˜๋ฉฐ ํ…Œ์ŠคํŠธ ์ฝ”๋“œ์˜ ์˜๋„๋งŒ ํ๋ฆฐ๋‹ค.
  • responder ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•˜๋Š” ์ฝ”๋“œ์™€ response๋ฅผ ์ˆ˜์ง‘ํ•ด ๋ณ€ํ™˜ํ•˜๋Š” ์ฝ”๋“œ ์—ญ์‹œ ์žก์Œ์— ๋ถˆ๊ณผํ•˜๋‹ค.
  • SerializedPageResponderTest.java (๋ฆฌํŒฉํ„ฐ๋งํ•œ ์ฝ”๋“œ)
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");
}

BUILD-OPERATE-CHECK ํŒจํ„ด์ด ์œ„์™€ ๊ฐ™์€ ํ…Œ์ŠคํŠธ ๊ตฌ์กฐ์— ์ ํ•ฉํ•˜๋‹ค. ๊ฐ ํ…Œ์ŠคํŠธ๋Š” ๋ช…ํ™•ํžˆ ์„ธ ๋ถ€๋ถ„์œผ๋กœ ๋‚˜๋ˆ ์ง„๋‹ค.

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

ํ…Œ์ŠคํŠธ ์ฝ”๋“œ๋Š” ๋ณธ๋ก ์— ๋Œ์ž…ํ•ด ์ง„์งœ ํ•„์š”ํ•œ ์ž๋ฃŒ ์œ ํ˜•๊ณผ ํ•จ์ˆ˜๋งŒ ์‚ฌ์šฉํ•œ๋‹ค.


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

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

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

EnvironmentControllerTest.java

@Test
public void turnOnLoTempAlarmAtThreashold() throws Exception {
    hw.setTemp(WAY_TOO_COLD);
    controller.tic();
    assertTrue(hw.heaterState());
    assertTrue(hw.blowerState());
    assertFalse(hw.coolerState());
    assertFalse(hw.hiTempAlarm());
    assertTrue(hw.loTempAlarm());
}

EnvironmentControllerTest.java (๋ฆฌํŒฉํ„ฐ๋ง)

@Test
public void turnOnLoTempAlarmThreshold() throws Exception {
    wayTooCold();
    assertEquals("HBchL", hw.getState());
}
public String getState() {
    String state = "";
    state += heater ? "H" : "h";
    state += blower ? "B" : "b";
    state += coolear ? "C" : "c";
    state += hiTempAlarm ? "H" : "h";
    state += loTempAlarm ? "L" : "l";
    return state;
}
  • ํ…Œ์ŠคํŠธ ๋‹น assert ํ•˜๋‚˜
    ํ…Œ์ŠคํŠธ ํ•จ์ˆ˜๋งˆ๋‹ค ํ•œ ๊ฐœ๋…๋งŒ ํ…Œ์ŠคํŠธํ•˜๋ผ
    addMonths() ๋ฉ”์„œ๋“œ๋ฅผ ํ…Œ์ŠคํŠธํ•˜๋Š” ์žฅํ™ฉํ•œ ์ฝ”๋“œ
public void testAddMonths() {
    SerialDate d1 = SerialDate.createInstance(31, 5, 2004);

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

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

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

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

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

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

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

๊ฒฐ๋ก 

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

์ฐธ๊ณ  ๋งํฌ

๋ฐ˜์‘ํ˜•