[Spring boot] Spring boot test starter๋ฅผ ์ด์šฉํ•œ ํ…Œ์ŠคํŠธ ์ฝ”๋“œ ์ž‘์„ฑ

๋ฐ˜์‘ํ˜•

์ง€๋‚œ ํฌ์ŠคํŠธ์—์„œ ์ž ๊น, ํ…Œ์ŠคํŠธ ์ฝ”๋“œ์— ๋Œ€ํ•ด ๋‹ค๋ค„๋ดค์—ˆ์Šต๋‹ˆ๋‹ค. ํ…Œ์ŠคํŠธ ์ฝ”๋“œ๋ฅผ ์ด์šฉํ•˜๋ฉด, ํ™•์‹คํžˆ Postman์ด๋‚˜ Curl๊ณผ ๊ฐ™์€ ํ…Œ์ŠคํŠธ ๋„๊ตฌ์—†์ด๋„ ์ž๋™ํ™” ๋œ ํ…Œ์ŠคํŠธ ํ”„๋ ˆ์ž„์›Œํฌ๋ฅผ ์ด์šฉํ•ด์„œ ์‰ฝ๊ฒŒ ํ…Œ์ŠคํŠธ๋ฅผ ํ•  ์ˆ˜ ์žˆ์—ˆ์ฃ .

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

 

Spring boot Test

Spring boot์—์„œ๋Š” ๊ธฐ๋ณธ์ ์ธ ํ…Œ์ŠคํŠธ ์Šคํƒ€ํ„ฐ๋ฅผ ์ œ๊ณตํ•˜๋Š”๋ฐ, ์ด ๋ชจ๋“ˆ์—๋Š” Junit ๋ฟ๋งŒ ์•„๋‹ˆ๋ผ ์™ ๋งŒํ•œ Java ๊ณ„์—ด์˜ ์–ธ์–ด์—์„œ ์‚ฌ์šฉํ•˜๋Š” ํ…Œ์ŠคํŠธ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋“ค์ด ํ•œ๋Œ€ ๋ชจ์—ฌ ์žˆ์Šต๋‹ˆ๋‹ค. 

  • spring-boot-test
  • spring-boot-test-autoconfigure

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

๊ธฐ๋ณธ์ ์œผ๋กœ ์•Œ๊ณ ๋ฆฌ์ฆ˜ ์ฝ”๋“œ๋ฅผ ์งœ๊ณ , ํ•˜๋Š” ํ…Œ์ŠคํŠธ๋ฅผ ์œ ๋‹› ํ…Œ์ŠคํŠธ, ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง ํ•˜๋‚˜๋ฅผ ๊ตฌํ˜„ํ•˜๊ณ  ์งœ๋Š” ํ…Œ์ŠคํŠธ ์—ญ์‹œ ์œ ๋‹› ํ…Œ์ŠคํŠธ๋ผ๊ณ  ํ•ฉ๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ์›น ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์—์„œ๋Š” ์œ ๋‹› ํ…Œ์ŠคํŠธ ๋˜ํ•œ ์ค‘์š”ํ•˜์ง€๋งŒ, UI Test, App Test, Data Test, JsonTest ๋“ฑ ๋‹ค์–‘ํ•˜๊ฒŒ ํ…Œ์ŠคํŠธ ๋ฒ”์œ„๊ฐ€ ๋„“ํ˜€์ ธ ์žˆ๋‹ค๋Š” ๊ฒƒ์ด ํฌ์ธํŠธ์ด๊ณ , ์‹ค์ œ ํ…Œ์ŠคํŠธ๋ฅผ ํ•  ๋•Œ๋Š” ์ด์— ๋Œ€ํ•œ ํ…Œ์ŠคํŠธ ์ฝ”๋“œ๋ฅผ ๋ณ„๋„๋กœ ๊ตฌ์„ฑํ•ด์•ผ ํ•œ๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

Spring boot starter test๋Š” ์ด๋Ÿฌํ•œ ํ…Œ์ŠคํŠธ๋ฅผ ์‰ฝ๊ฒŒ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ๋„๋ก ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๋‹ค์–‘ํ•œ ์–ด๋…ธํ…Œ์ด์…˜์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.

  • @SpringBootTest
  • @WebMvcTest
  • @DataJpaTest
  • @RestClientTest
  • @JsonTest

์ด ์™ธ์—๋„ Spring boot 2.x์—์„œ ์ถ”๊ฐ€๋œ ์ƒˆ๋กœ์šด ์–ด๋…ธํ…Œ์ด์…˜๋„ ์กด์žฌํ•ฉ๋‹ˆ๋‹ค.

  • @WebFluxTest
  • @JooqTest
  • @DataLdapTest
  • @DataNeo4jTest
  • @DataRedisTest

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

 

@SpringBootTest

SpringBootTest ์–ด๋…ธํ…Œ์ด์…˜์€ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๋ ˆ๋ฒจ์˜ ํ…Œ์ŠคํŠธ์ž…๋‹ˆ๋‹ค. ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๋ ˆ๋ฒจ์˜ ํ…Œ์ŠคํŠธ๋ž€, ์„œ๋ฒ„ ํ”„๋กœ๊ทธ๋žจ์˜ ํ™˜๊ฒฝ ์„ค์ •์ด๋‚˜ ํฌํŠธ ์ฃผ์†Œ ๋“ฑ ์‹คํ–‰๋  ๋•Œ์˜ ๋Ÿฐํƒ€์ž„ ํ…Œ์ŠคํŠธ๋ฅผ ๋งํ•ฉ๋‹ˆ๋‹ค.

ํŠนํžˆ ์—ฌ๋Ÿฌ ๋‹จ์œ„ ํ…Œ์ŠคํŠธ๋ฅผ ํ•˜๋‚˜์˜ ํ†ตํ•ฉ๋œ ํ…Œ์ŠคํŠธ๋กœ ์ˆ˜ํ–‰ํ•  ๋•Œ ์ ํ•ฉํ•œ๋ฐ, Spring boot 1.4 ๋ฒ„์ „๋ถ€ํ„ฐ ์ œ๊ณต๋˜๊ณ , ์šฐ๋ฆฌ๊ฐ€ ์ง€๋‚œ ํฌ์ŠคํŠธ์—์„œ๋„ ๊ฐ™์ด ์‚ฌ์šฉํ•œ ์–ด๋…ธํ…Œ์ด์…˜์ž…๋‹ˆ๋‹ค. ์ด ์–ด๋…ธํ…Œ์ด์…˜์„ ์ˆ˜ํ–‰ํ•˜๋ฉด, ์ง์ ‘ ์„œ๋ฒ„ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์ด ์ž๋™์œผ๋กœ ์˜ฌ๋ผ๊ฐ€๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

์ด ์–ด๋…ธํ…Œ์ด์…˜์˜ ์ž‘๋™ ์›๋ฆฌ๋Š” ์‹ค์ œ ๊ตฌ๋™๋˜๋Š” ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜๊ณผ ๋˜‘๊ฐ™์ด Application Context๋ฅผ ๋กœ๋“œํ•˜์—ฌ ํ…Œ์ŠคํŠธํ•˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค. ์•ˆ๋“œ๋กœ์ด๋“œ๋กœ ๋ณด์ž๋ฉด, Instrument Test๋ผ๊ณ  ํ•ด์„œ, ์ง์ ‘ VM์— ๊ธฐ๊ธฐ๋ฅผ ์˜ฌ๋ฆฌ๊ณ  ํ•˜๋Š” ํ…Œ์ŠคํŠธ์ด๊ธฐ ๋•Œ๋ฌธ์— ํ…Œ์ŠคํŠธ ์†๋„๊ฐ€ ์—„์ฒญ ๋Š๋ฆฐ ๋ฐ˜๋ฉด, ๋ชจ๋“  ํ…Œ์ŠคํŠธ๋ฅผ ํ•  ์ˆ˜ ์žˆ์ฃ . ๋”ฐ๋ผ์„œ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ์ข…ํ•ฉ์ ์ธ ํ…Œ์ŠคํŠธ๋ฅผ ํ•˜๊ณ ์ž ํ•  ๋•Œ ์ ํ•ฉํ•ฉ๋‹ˆ๋‹ค.

๊ทธ๋Ÿผ ๊ฐ„๋‹จํ•˜๊ฒŒ ํ…Œ์ŠคํŠธ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•ด๋ณด๋„๋ก ํ•˜์ฃ .

์–ด๋…ธํ…Œ์ด์…˜์— ๋Œ€ํ•œ ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ ๊ฐ๊ฐ ์„ค๋ช…๋“œ๋ฆฌ์ž๋ฉด...

  • value: ํ…Œ์ŠคํŠธ๊ฐ€ ์‹คํ–‰๋˜๊ธฐ ์ „์— ์ ์šฉํ•  Property๋กœ, ๊ธฐ์กด์˜ Property๋ฅผ Override ํ•ฉ๋‹ˆ๋‹ค.
  • properties: ํ…Œ์ŠคํŠธ๊ฐ€ ์‹คํ–‰๋˜๊ธฐ ์ „์—, {key=value} ํ˜•์‹์œผ๋กœ Property๋ฅผ ์ถ”๊ฐ€ ํ•ฉ๋‹ˆ๋‹ค.
  • classes: Application Context์— ๋กœ๋“œํ•  ํด๋ž˜์Šค๋ฅผ ์ง€์ •ํ•ฉ๋‹ˆ๋‹ค. ๋ณ„๋„๋กœ ์ง€์ •ํ•˜์ง€ ์•Š์„ ๊ฒฝ์šฐ, @SpringBootConfiguration์„ ์ฐพ์•„์„œ ๋กœ๋“œํ•˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.
  • webEnvironment: ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์ด ์‹คํ–‰๋  ๋–„์˜ ์›น ํ™˜๊ฒฝ์œผ๋กœ, ๊ธฐ๋ณธ๊ฐ’์€ ๊ธฐ๋ณธ ์„ค์ •๋œ Mock Servlet์„ ๋กœ๋“œํ•ฉ๋‹ˆ๋‹ค. ๊ฑฐ๊ธฐ์— ์ถ”๊ฐ€๋กœ, ์œ„ ์ฝ”๋“œ์—์„œ๋Š” ํฌํŠธ ์ฃผ์†Œ๋ฅผ ๋žœ๋ค์œผ๋กœ ํ•œ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

์œ„ ์ฝ”๋“œ๋ฅผ ์‹คํ–‰ํ•˜๋ฉด, ์‹ค์ œ๋กœ๋Š” ์‹คํ–‰๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์–ด๋–ค ์˜ค๋ฅ˜๊ฐ€ ๋‚˜ํƒ€๋‚˜๋ƒ๋ฉด, value์™€ properties๋ฅผ ๊ฐ™์ด ์‚ฌ์šฉํ•  ์ˆ˜ ์—†๋‹ค๋Š” ์˜ค๋ฅ˜๊ฐ€ ๋‚˜ํƒ€๋‚˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

๋‘ ํŒŒ๋ผ๋ฏธํ„ฐ๊ฐ€ ๋‹ค๋ฅธ ์ ์€ ์•„๋ž˜์™€ ๊ฐ™์Šต๋‹ˆ๋‹ค.

value๋Š” ๊ธฐ์กด์˜ properties ์—…๋ฐ์ดํŠธํ•˜๋Š” ๋ฐ˜๋ฉด, properties๋Š” ์ƒˆ๋กœ ์ถ”๊ฐ€๋œ๋‹ค๋Š” ์†์„ฑ์„ ์ง€๋‹ˆ๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ ๋‘ ๊ฐœ์˜ ํŒŒ๋ผ๋ฏธํ„ฐ์— ๊ฐ™์€ ๊ฐ’์„ ๋„ฃ๋Š” ๊ฒƒ์€ ์•ˆ๋ฉ๋‹ˆ๋‹ค.

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

๊ทธ๋Ÿด ๋•Œ๋Š” YAML ํŒŒ์ผ์„ ํ•˜๋‚˜ ๊ตฌ์„ฑํ•ด๋†“๊ณ , @ActiveProfiles ์–ด๋…ธํ…Œ์ด์…˜์„ ์ด์šฉํ•ด์ฃผ๋ฉด ๋ฉ๋‹ˆ๋‹ค.

์–ด๋…ธํ…Œ์ด์…˜์— ์ ์šฉํ•  ํ”„๋กœํŒŒ์ผ ์ด๋ฆ„์„ ๋„ฃ์–ด์ฃผ๋ฉด ๋.

์‹คํ–‰ํ•ด๋ณด๋ฉด, test ํ™˜๊ฒฝ์œผ๋กœ ์‹คํ–‰๋˜์—ˆ์Œ์„ ์•Œ ์ˆ˜ ์žˆ๊ณ , ํฌํŠธ ์ฃผ์†Œ๋Š” ๋žœ๋ค๋œ ๋ฒˆํ˜ธ๋กœ ๋ถ€์—ฌ๋˜๊ณ  ์žˆ์Œ์„ ์•Œ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ด ์™ธ์—๋„, ํŒ์ด ์žˆ๋‹ค๋ฉด, ํ…Œ์ŠคํŠธ ํ™˜๊ฒฝ์—์„œ ํ…Œ์ŠคํŠธ๋ฅผ ์ˆ˜ํ–‰ํ•  ๊ฒฝ์šฐ, ํŠนํžˆ DB์˜ ๊ฒฝ์šฐ @Transactional์ด ์ ์šฉ๋œ ์ฝ”๋“œ์— ๋Œ€ํ•ด์„œ๋Š” ์˜ค์ง ํ…Œ์ŠคํŠธ๋งŒ ์ˆ˜ํ–‰ํ•˜๋Š” ๊ฒƒ์ด๊ธฐ ๋•Œ๋ฌธ์— ๋กค๋ฐฑ์ด ๋ฉ๋‹ˆ๋‹ค.

๊ทธ๋Ÿฌ๋‚˜, ํ…Œ์ŠคํŠธ๊ฐ€ ์„œ๋ฒ„์˜ ๋‹ค๋ฅธ ์Šค๋ ˆ๋“œ์—์„œ ์‹คํ–‰ ์ค‘์ผ ๊ฒฝ์šฐ์—๋Š” RANDOM_PORT๋‚˜ DEFINED_PORT๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ํ…Œ์ŠคํŠธ๋ฅผ ์ˆ˜ํ–‰ํ•ด๋„ ํŠธ๋žœ์žญ์…˜์ด ๋กค๋ฐฑ๋˜์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์—, CI/CD ํ™˜๊ฒฝ ๊ตฌ์„ฑ์— ์ฐธ๊ณ  ํ•˜์‹œ๋Š” ๊ฒŒ ์ข‹๊ฒ ์Šต๋‹ˆ๋‹ค.

๋˜ ํ•œ๊ฐ€์ง€๋Š” @SpringBootTest ์–ด๋…ธํ…Œ์ด์…˜์—๋Š” ๊ธฐ๋ณธ์ ์œผ๋กœ Spring boot Application ํด๋ž˜์Šค๋ฅผ ์ฐพ๋Š” ๊ฒ€์ƒ‰ ์•Œ๊ณ ๋ฆฌ์ฆ˜์ด ์ ์šฉ๋˜์–ด ์žˆ๋Š”๋ฐ, ์œ„์—์„œ ์„ค๋ช…ํ–ˆ๋‹ค์‹œํ”ผ @SpringBootApplication ํ˜น์€ @SpringBootConfiguration ์–ด๋…ธํ…Œ์ด์…˜์„ ์ฐพ๊ธฐ ๋•Œ๋ฌธ์— ๋ฐ˜๋“œ์‹œ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์— ์ด๋Ÿฌํ•œ ์–ด๋…ธํ…Œ์ด์…˜์„ ๋ช…์‹œํ•ด์ฃผ๋„๋ก ํ•ฉ์‹œ๋‹ค.

 

@WebMvcTest

์ด๋ฆ„ ๊ทธ๋Œ€๋กœ MVC๋ฅผ ์œ„ํ•œ ํ…Œ์ŠคํŠธ์ž…๋‹ˆ๋‹ค. ๋Œ€ํ‘œ์ ์œผ๋กœ ์›น์—์„œ ํ…Œ์ŠคํŠธํ•˜๊ธฐ ์–ด๋ ค์šด Controller ํ…Œ์ŠคํŠธ๋“ค์ด ์žˆ์Šต๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์ž๋ฉด, Form์— ์—ฌ๋Ÿฌ๊ฐ€์ง€ ๋ฐ์ดํ„ฐ๋ฅผ ํ•œ ๋ฒˆ์— ์ž…๋ ฅํ•˜๊ณ , ํ…Œ์ŠคํŠธ ํ–ˆ๋Š”๋ฐ, ๋‹ค์‹œ ๋˜ ํ…Œ์ŠคํŠธ๋ฅผ ๋ฐ˜๋ณตํ•ด์•ผ ํ•œ๋‹ค๋ฉด? ๋‹ค์‹œ ๊ฐ’์„ ์ž…๋ ฅํ•ด์•ผ ํ•˜๊ณ , ์†์ด ๋งŽ์ด ๊ฐ€์ฃ .

์›น ์ƒ์—์„œ Request, Response์— ๋Œ€ํ•ด ํ…Œ์ŠคํŠธํ•  ์ˆ˜ ์žˆ๋Š” ์–ด๋…ธํ…Œ์ด์…˜์ด๊ณ , ์‹ฌ์ง€์–ด Spring Security์—์„œ ์ œ๊ณตํ•˜๋Š” ๋กœ๊ทธ์ธ, ๋กœ๊ทธ์•„์›ƒ, ์„ธ์…˜, ํ•„ํ„ฐ๊นŒ์ง€ ์ž๋™์œผ๋กœ ํ…Œ์ŠคํŠธํ•  ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ๋งค์šฐ ์œ ์šฉํ•ฉ๋‹ˆ๋‹ค.

์œ„์—์„œ ๋‹ค๋ค„๋ณธ @SpringBootTest ์–ด๋…ธํ…Œ์ด์…˜์—์„œ๋„ ์ด๋Ÿฌํ•œ ํ…Œ์ŠคํŠธ๊ฐ€ ๊ฐ€๋Šฅํ•˜์ง€๋งŒ, @WebMvcTest๋Š” ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์ปจํ…์ŠคํŠธ๋ฅผ ํ†ตํ•ด ์„œ๋ฒ„ ์•ฑ์„ ์ „๋ถ€ ๋กœ๋“œํ•˜๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋ผ MVC ๊ด€๋ จ ์–ด๋…ธํ…Œ์ด์…˜์ธ @Controller, @ControllerAdvice, @JsonComponent์™€ Filter, WebConfigurer, HandlerMethodArgumentResolver๋งŒ ๋กœ๋“œ๋˜๊ธฐ ๋•Œ๋ฌธ์— ๊ฐ€๋ณ๊ฒŒ ํ…Œ์ŠคํŠธํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ์žฅ์ ์ด ์žˆ์Šต๋‹ˆ๋‹ค.

๊ฐ„๋‹จํ•˜๊ฒŒ ํ…Œ์ŠคํŠธํ•ด๋ณด๊ธฐ ์œ„ํ•ด POJO ๊ฐ์ฒด์™€ ์ด๋ฅผ ์ˆ˜ํ–‰ํ•˜๋Š” Controller๋ฅผ ํ•˜๋‚˜ ๋งŒ๋“ค์–ด๋ณด๋„๋ก ํ•˜์ฃ .

Kotlin์—์„œ ์ œ๊ณตํ•˜๋Š” data class๋ฅผ ์ด์šฉํ•ด, ์ƒํ’ˆ ๋ฒˆํ˜ธ, ์ƒํ’ˆ ์ด๋ฆ„, ์ƒํ’ˆ ๊ฐ€๊ฒฉ, ์ƒํ’ˆ ์ž…๊ณ  ๋‚ ์งœ๋ฅผ ๊ฐ€์ง„ ํ•„๋“œ์˜ POJO ๊ฐ์ฒด๋ฅผ ๋งŒ๋“ค์–ด๋ณด๋„๋ก ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

Controller ์ฝ”๋“œ๋Š” ์ƒํ’ˆ ๋ฆฌ์ŠคํŠธ๋ฅผ ๋ฐ›์•„์˜ค๋Š” ์ฝ”๋“œ์ž…๋‹ˆ๋‹ค. ์—”๋“œํฌ์ธํŠธ๋กœ "/books"๋ผ๋Š” ํฌ์ธํŠธ์— GET ๋ฉ”์†Œ๋“œ ์š”์ฒญ์‹œ, BookService ํด๋ž˜์Šค์— ์ƒํ’ˆ ๋ชฉ๋ก์„ ์š”์ฒญํ•˜์—ฌ, "itemList"๋ผ๋Š” ํ‚ค ๊ฐ’์œผ๋กœ ๋ฐ์ดํ„ฐ๊ฐ’์„ ๋„˜๊ธฐ๋Š” Controller์ž…๋‹ˆ๋‹ค. Controller์—์„œ ๋ฐ˜ํ™˜๋˜๋Š” View ์ด๋ฆ„์€ "item"์œผ๋กœ ์ง€์ •ํ•˜์˜€์Šต๋‹ˆ๋‹ค.

๋‹ค์Œ๊ณผ ๊ฐ™์ด ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ์ƒ์„ฑํ•ด์ค๋‹ˆ๋‹ค. ์ธํ„ฐํŽ˜์ด์Šค๋Š” Item ํƒ€์ž…์˜ ๋ฆฌ์ŠคํŠธ๋ฅผ ๋„˜๊ธฐ๋Š” ๋ฉ”์†Œ๋“œ ํ•˜๋‚˜๋งŒ์„ ๋งŒ๋“ค์—ˆ์Šต๋‹ˆ๋‹ค. ์‹ค์ œ๋กœ ์ด ์ธํ„ฐํŽ˜์ด์Šค๋Š”๋ฅผ ๊ตฌํ˜„ํ•˜๋Š” ๊ตฌํ˜„์ฒด๋Š” ๋งŒ๋“ค์ง€ ์•Š๊ฒ ์Šต๋‹ˆ๋‹ค. (๋‹จ์ˆœ ํ…Œ์ŠคํŠธ๋งŒ ์ง„ํ–‰ํ•  ๊ฒƒ์ด๊ธฐ ๋•Œ๋ฌธ์—..) ๊ตฌํ˜„์ฒด๊ฐ€ ์—†๋Š” ๋Œ€์‹  Mock ๋ฐ์ดํ„ฐ๋ฅผ ์ด์šฉํ•ด์„œ ํ…Œ์ŠคํŠธ๋ฅผ ์ง„ํ–‰ํ•˜๋„๋ก ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

@WebMvcTest๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•ด์„œ ๋จผ์ € ํ•ด์•ผํ•  ์ผ์€ ํ…Œ์ŠคํŠธํ•  ํŠน์ • Controller์˜ ํด๋ž˜์Šค ์ด๋ฆ„์„ ๋ช…์‹œํ•ด์ค˜์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์ฃผ์ž…๋œ MockMvc๋Š” Controller ํ…Œ์ŠคํŠธ์‹œ, ๋ชจ๋“  ์˜์กด์„ฑ์„ ๋กœ๋“œํ•˜๋Š” ๊ฒƒ์ด ์•„๋‹Œ ItemController ๊ด€๋ จ Bean๋งŒ์„ ๋กœ๋“œํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๊ฐ€๋ฒผ์šด MVC ํ…Œ์ŠคํŠธ ์ˆ˜ํ–‰์ด ์ด๋ฃจ์–ด์ง€๋ฉฐ, ์ด ๋•Œ๋Š” ์ „์ฒด HTTP ์„œ๋ฒ„๋ฅผ ์‹คํ–‰ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

@Service ์–ด๋…ธํ…Œ์ด์…˜์ด ์ ํ˜€์žˆ๋Š” ItemService๋Š” ์‹ค์ œ @WebMvcTest ์ ์šฉ ๋Œ€์ƒ์€ ์•„๋‹™๋‹ˆ๋‹ค. ๋‹ค๋งŒ ItemService ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๊ตฌํ˜„ํ•œ ๊ตฌํ˜„์ฒด ์—†์ด ๊ฐ€์งœ ๊ฐ์ฒด๋กœ ๋Œ€์ฒดํ•ด์•ผ๋งŒ Controller์—์„œ ํ•ด๋‹น ๋ฉ”์†Œ๋“œ๋ฅผ ์ด์šฉํ•  ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์— @MockBean์„ ํ™œ์šฉํ•˜์—ฌ Controller ๋‚ด๋ถ€์˜ ์˜์กด์„ฑ ์š”์†Œ๋ฅผ ๋งˆ์น˜ ์ง„์งœ์ธ ๊ฒƒ์ฒ˜๋Ÿผ ์†์ธ ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์—ฌ๊ธฐ์„œ ๊ฐ€์งœ ๊ฐ์ฒด๋ฅผ Mock Object๋ผ๊ณ  ์ด์•ผ๊ธฐ ํ•ฉ๋‹ˆ๋‹ค. ์‹ค์ฒด ๊ฐ์ฒด๋Š” ์•„๋‹ˆ์ง€๋งŒ ํŠน์ • ํ–‰์œ„๋ฅผ ์ง€์ •ํ•˜์—ฌ ์‹ค์ œ ๊ฐ์ฒด์ฒ˜๋Ÿผ ๋™์ž‘ํ•˜๊ฒŒ ๋งŒ๋“ค ์ˆ˜ ์žˆ๋Š” ์š”์†Œ์ž…๋‹ˆ๋‹ค.

@MockBean์„ ์‚ฌ์šฉํ•  ๊ฒฝ์šฐ, ๊ฐ์ฒด๋Š” ๊ฐ€์งœ์ง€๋งŒ ํ–‰์œ„๋Š” ์ง„์งœ์ฒ˜๋Ÿผ ํ–‰๋™ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์‹ค์ œ๋กœ getItemList()์—์„œ item์„ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค. ์ด ๋•Œ ํ…Œ์ŠคํŠธ๋ฅผ ์ง„ํ–‰ํ•  ๊ฒฝ์šฐ, given() ๋ฉ”์†Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์‹ค์ œ ๋ฆฌ์ŠคํŠธ์— ๋ฐ์ดํ„ฐ๋ฅผ ๋„ฃ์–ด์ค˜์•ผํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋ž˜์•ผ๋งŒ ์ตœ์ข…์ ์œผ๋กœ ์ด๊ฒƒ์ด ๋ฐ˜ํ™˜๋˜๋Š”์ง€ ํ…Œ์ŠคํŠธ๋ฅผ ํ•  ์ˆ˜ ์žˆ๊ฒ ์ฃ ?

์—ฌ๊ธฐ๊นŒ์ง€ ๋๋‚ฌ์œผ๋ฉด, ๋งˆ์ง€๋ง‰์œผ๋กœ MockMvc๋ฅผ ์‚ฌ์šฉํ•ด ํ•ด๋‹น URL์˜ ์ƒ๋Œ“๊ฐ’, ๋ฐ˜ํ™˜๊ฐ’์— ๋Œ€ํ•œ ํ…Œ์ŠคํŠธ๋ฅผ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

  • andExpect(status().isOk): HTTP ์‘๋‹ต๊ฐ’์ด 200์ธ์ง€ ํ…Œ์ŠคํŠธ (200์€ ์„ฑ๊ณต์„ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค.)
  • andExpect(view().name("item")): ๋ฐ˜ํ™˜๋˜๋Š” ๋ทฐ์˜ ์ด๋ฆ„์ด "item"์ธ์ง€ ํ…Œ์ŠคํŠธ
  • andExpect(model().attributeExists("itemList")): ๋ชจ๋ธ์˜ property ์ค‘ "itemList"๋ผ๋Š” property๊ฐ€ ์กด์žฌํ•˜๋Š”์ง€ ํ…Œ์ŠคํŠธ
  • andExpect(model().attribute("itemList", contains(item))): ๋ชจ๋ธ์˜ property ์ค‘ "itemList"๋ผ๋Š” property์— item ๊ฐ์ฒด๊ฐ€ ๋‹ด๊ฒจ์ ธ ์žˆ๋Š”์ง€ ํ…Œ์ŠคํŠธ

์ด ํ…Œ์ŠคํŠธ๋Š” Spring MVC์ผ ๋•Œ ์œ ์šฉํ•˜๊ฒŒ ์“ฐ์ผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

 

@DataJpaTest

์•„์ง JPA์— ๋Œ€ํ•ด ๋‹ค๋ฃจ์ง„ ์•Š์•˜์ง€๋งŒ, ๊ฐ„๋‹จํžˆ ์„ค๋ช…๋“œ๋ฆฌ์ž๋ฉด, JPA๋Š” Spring boot์—์„œ DB์™€ ์—ฐ๋™ํ•˜๊ธฐ ์œ„ํ•œ ๋ชจ๋“ˆ์ž…๋‹ˆ๋‹ค. ๊ณผ๊ฑฐ์—๋Š” Batis ๋“ฑ์„ ์ด์šฉํ•ด SQL ์งˆ์˜๋ฅผ ์ง์ ‘ ์ž‘์„ฑํ•˜๋Š” ๊ฒฝ์šฐ๊ฐ€ ๋งŽ์•˜์ง€๋งŒ ์ตœ๊ทผ์—๋Š” ORM์ด ๋Œ€์„ธ๋ฅผ ์ด๋ฃจ๋ฉด์„œ JPA๋ฅผ ์ด์šฉํ•œ DB ์—ฐ๋™์ด ๋” ๋งŽ์•„์ง€๋Š” ์ถ”์„ธ์ฃ .

@DataJpaTest๋Š” JPA ๊ด€๋ จ ํ…Œ์ŠคํŠธ ์„ค์ •๋งŒ์„ ๋กœ๋“œํ•˜๋Š”๋ฐ, DataSource์˜ ์„ค์ •์ด ์œ ํšจํ•œ์ง€ ํ˜น์€ ์ •์ƒ์ธ์ง€, JPA๋ฅผ ์ด์šฉํ•ด DDL, DML์ด ์ •์ƒ์ ์œผ๋กœ ์ˆ˜ํ–‰๋˜๋Š”์ง€ ๋“ฑ์˜ ํ…Œ์ŠคํŠธ๊ฐ€ ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค. ๋ฌผ๋ก  ํ…Œ์ŠคํŠธ ํ•˜๋Š” ๋ฐฉ๋ฒ•์€ Docker, Kubernetes ๋“ฑ ๋‹ค์–‘ํ•œ ํ™˜๊ฒฝ์„ ์ด์šฉํ•  ์ˆ˜๋„ ์žˆ๊ฒ ์ง€๋งŒ, Spring boot์—์„œ๋Š” H2๋ผ๋Š” In-memory DB๋ฅผ ๊ธฐ๋ณธ์ ์œผ๋กœ ์ œ๊ณตํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์ด๋ฅผ ์ด์šฉํ•ด๋„ ๊ดœ์ฐฎ์Šต๋‹ˆ๋‹ค.

์‹ค์ œ๋กœ @ActiveProfiles๋Š” ์ด๊ฒƒ ๋•Œ๋ฌธ์— ๋งŽ์ด ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค. ์šด์˜ DB์—์„œ ๋ฒ„๊ทธ๋ฅผ ์ˆ˜์ •ํ•˜๊ณ , ํ•˜๋Š” ์ผ์€ ์žˆ์–ด์„œ๋Š” ์•ˆ๋˜๊ธฐ ๋•Œ๋ฌธ์— ๊ฐœ๋ฐœ์šฉ DB, ํ…Œ์ŠคํŠธ์šฉ DB๋ฅผ ๋ณ„๋„๋กœ ๊ตฌ์ถ•ํ•˜์—ฌ ์‚ฌ์šฉํ•˜๋Š” ํŽธ์ธ๋ฐ, ์ด๋“ค DataSource ์„ค์ •์ด ์ „๋ถ€ ๋‹ค๋ฅด๋‹ˆ, ๊ฐœ๋ฐœํ•  ๋•Œ ๋ฐ”๊พธ๊ณ  ํ…Œ์ŠคํŠธํ•  ๋•Œ ๋ฐ”๊ฟ€ ์ˆ˜๊ฐ€ ์—†๊ธฐ ๋•Œ๋ฌธ์— ํ™˜๊ฒฝ ์„ค์ •์„ ํ”„๋กœํผํ‹ฐ๋ฅผ ํ†ตํ•ด ์„ค์ •ํ•˜๋Š” ๊ฒƒ์ด์ฃ .

๋จผ์ € ํ…Œ์ŠคํŠธ๋ฅผ ์œ„ํ•ด Data class๋ฅผ ์ด์šฉํ•ด์„œ Item์— ๋Œ€ํ•œ Entity ํด๋ž˜์Šค๋ฅผ ๋งŒ๋“ค์–ด์ค๋‹ˆ๋‹ค. Item ๋„๋ฉ”์ธ ๊ฐ์ฒด์— JPA ํ…Œ์ŠคํŠธ๋ฅผ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ๊ฒŒ Item ํด๋ž˜์Šค์— JPA ๊ด€๋ จ ์–ด๋…ธํ…Œ์ด์…˜๋งŒ์„ ์ถ”๊ฐ€ํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค.

JPA ๊ถŒ์žฅ์— ๋”ฐ๋ผ Repository ํŒจํ„ด์„ ๋งž์ถฐ ItemRepository ์ธํ„ฐํŽ˜์ด์Šค๋„ ๊ฐ™์ด ๋งŒ๋“ค์–ด์ค๋‹ˆ๋‹ค.

์ด๋ฒˆ์—๋Š” ์ƒ์„ฑ์ž ์ฃผ์ž… ๋ฐฉ์‹์œผ๋กœ EntityManager์™€ Repository๋ฅผ ์ฃผ์ž…ํ•˜์˜€๊ณ , ํ…Œ์ŠคํŠธ ์ฝ”๋“œ๋Š” ์ด 3๊ฐœ๋กœ ๊ตฌ๋ถ„ํ•˜์˜€์Šต๋‹ˆ๋‹ค. Item์ด๋ผ๋Š” ๋žœ๋ค์˜ ์ƒํ’ˆ์„ ์ƒ์„ฑํ•˜๊ณ , testEntityManager์˜ persist ๋ฉ”์†Œ๋“œ๋ฅผ ์ด์šฉํ•˜๋ฉด ์ •์ƒ ๋™์ž‘ํ•˜๋Š”์ง€๋ฅผ ํ…Œ์ŠคํŠธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

IsEmptyCollection์€ Collection ์ž๋ฃŒ๊ตฌ์กฐ๊ฐ€ ๋น„์–ด ์žˆ๋Š”์ง€๋ฅผ ํ…Œ์ŠคํŠธํ•˜๋Š” ํด๋ž˜์Šค๋กœ empty ๋ฉ”์†Œ๋“œ๋Š” ๋น„์–ด ์žˆ๋Š” Collection ์ž๋ฃŒ๊ตฌ์กฐ๋ฅผ ์ƒ์„ฑํ•˜๊ฒŒ ๋˜๋Š”๋ฐ, ์ด์™€ ์ผ์น˜ํ•˜๋ฉด ํ…Œ์ŠคํŠธ๋ฅผ ํ†ต๊ณผ์‹œํ‚ค๋„๋ก ๊ตฌํ˜„ํ•˜์˜€์Šต๋‹ˆ๋‹ค.

๋ชจ๋“  ํ…Œ์ŠคํŠธ๋Š” H2 DB์—์„œ ์ด๋ฃจ์–ด์ง€๋ฉฐ, ์œ„์—์„œ ์„ค๋ช…ํ–ˆ๋˜๋Œ€๋กœ ํ…Œ์ŠคํŠธ๊ฐ€ ์ข…๋ฃŒ๋˜๋ฉด ๋ชจ๋“  ๋ฐ์ดํ„ฐ๋Š” ๋กค๋ฐฑ๋ฉ๋‹ˆ๋‹ค.

 

@RestClientTest

์ด์ „ ํฌ์ŠคํŠธ์—์„œ๋Š” REST ๊ด€๋ จ ํ…Œ์ŠคํŠธ๋ฅผ ์œ„ํ•ด Curl์ด๋‚˜ Postman์„ ์†Œ๊ฐœํ•˜์˜€์Šต๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ์ด๋“ค์˜ ํ…Œ์ŠคํŠธ๋Š” ๋‹จ์œ„ ํ…Œ์ŠคํŠธ์— ๋ถˆ๊ณผํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์ผ์ผ์ด ์ˆ˜๋™์œผ๋กœ ์ „์ฒด์ ์ธ ํ…Œ์ŠคํŠธ๋ฅผ ์ง„ํ–‰ํ•˜๋Š” ๋ฐ๋Š” ํ•œ๊ณ„๊ฐ€ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค.

REST ํ†ต์‹ ์— ๊ด€๋ จ๋œ ํ…Œ์ŠคํŠธ์˜ ์ฃผ๋Š” ๋Œ€๋ถ€๋ถ„ JSON ํ˜•์‹์— ๋งž์ถฐ ์˜ˆ์ƒ๋Œ€๋กœ ๋ฐ˜ํ™˜ํ•˜๋Š”์ง€์— ๋Œ€ํ•œ ํ…Œ์ŠคํŠธ๊ฐ€ ๋Œ€๋ถ€๋ถ„์ž…๋‹ˆ๋‹ค. ์œ„์˜ ํ…Œ์ŠคํŠธ๊ฐ€ DB์™€ ์ •์ƒ์ ์œผ๋กœ ํ†ต์‹ ํ•˜๊ณ  ์ œ๋Œ€๋กœ ํŠธ๋žœ์žญ์…˜์ด ๋˜๊ณ  ์žˆ๋Š”์ง€์— ๋Œ€ํ•œ ๋‚ด๋ถ€ ํ…Œ์ŠคํŠธ์˜€๋‹ค๋ฉด, ์ด๋ฒˆ ํ…Œ์ŠคํŠธ๋Š” ํด๋ผ์ด์–ธํŠธ์˜ ์š”์ฒญ์„ ์„œ๋ฒ„๊ฐ€ ์ •์ƒ์ ์œผ๋กœ ์ˆ˜ํ–‰ํ•˜๋Š”์ง€์— ๋Œ€ํ•œ ํ…Œ์ŠคํŠธ๋ผ๊ณ  ๋ณด์‹œ๋ฉด ๋ฉ๋‹ˆ๋‹ค.

ํ…Œ์ŠคํŠธ๋ฅผ ์œ„ํ•ด์„œ ๊ฐ„๋‹จํ•œ API ํ•œ ๊ฐœ๋ฅผ ๋งŒ๋“ค์–ด๋ณด๋„๋ก ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

๋จผ์ € RestService ํด๋ž˜์Šค๋ฅผ ํ•œ ๊ฐœ ๋งŒ๋“ค์–ด๋ณด๋„๋ก ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค. ์ด ํด๋ž˜์Šค์—์„œ ์‚ฌ์šฉํ•˜๋Š” RestTemplate์€ ์‹ค์ œ URI์—์„œ ์ž์›์„ ์š”์ฒญํ•˜๋Š” ๊ฐ์ฒด๋กœ TimeOut, ReadTimeOut ๋“ฑ ๋‹ค์–‘ํ•œ ์„ค์ •์ด ๊ฐ€๋Šฅํ•ด์„œ ํ…Œ์ŠคํŠธํ•˜๊ธฐ ์šฉ์ดํ•œ ํด๋ž˜์Šค์ฃ .

GET ๋ฐฉ์‹์œผ๋กœ ํ†ต์‹ ํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” getForObject, POST ๋ฐฉ์‹์€ postForObject๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๋˜๋Š”๋ฐ, ์—ฌ๊ธฐ์—์„œ๋Š” GET ๋ฐฉ์‹์œผ๋กœ ํ…Œ์ŠคํŠธ๋ฅผ ์ง„ํ–‰ํ•ด๋ณด๋„๋ก ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

์œ„์—์„œ ๋งŒ๋“ค์—ˆ๋˜ RestService๋ฅผ ์ฃผ์ž…ํ•˜๊ณ , GET ๋ฐฉ์‹์˜ API๋ฅผ ๋งŒ๋“ญ๋‹ˆ๋‹ค.

@RestClientTest ์—ญ์‹œ ํ…Œ์ŠคํŠธ ๋Œ€์ƒ์ด ๋˜๋Š” Bean์„ ์ฃผ์ž… ๋ฐ›์Šต๋‹ˆ๋‹ค. MockRestServiceServer ํด๋ž˜์Šค๋Š” ํด๋ผ์ด์–ธํŠธ์™€ ์„œ๋ฒ„ ์‚ฌ์ด์˜ REST ํ…Œ์ŠคํŠธ๋ฅผ ์œ„ํ•œ ๊ฐ์ฒด์ž…๋‹ˆ๋‹ค. ์‹ค์ œ๋กœ ํ†ต์‹ ์ด ์ด๋ฃจ์–ด์ง€๊ฒŒ๋” ๊ตฌ์„ฑํ•  ์ˆ˜๋„ ์žˆ์ง€๋งŒ ์œ„ ์ฝ”๋“œ์—์„œ๋Š” ์‹ค์ œ๋กœ ํ†ต์‹ ๊นŒ์ง€๋Š” ์ด๋ฃจ์–ด์ง€์ง€ ์•Š๊ณ , ์ง€์ •ํ•œ ๊ฒฝ๋กœ์— ์˜ˆ์ƒ๋˜๋Š” ์„ฑ๊ณต ๊ฒฐ๊ณผ, ์‹คํŒจ ๊ฒฐ๊ณผ๊ฐ€ ์•Œ๋งž๊ฒŒ ๋–จ์–ด์ง€๋Š”์ง€๋งŒ ๊ฐ„๋‹จํžˆ ๋ณด๋Š” ํ…Œ์ŠคํŠธ ์ฝ”๋“œ์ž…๋‹ˆ๋‹ค.

andRespond ๋ฉ”์†Œ๋“œ๋ฅผ ์ด์šฉํ•˜์—ฌ ์—ฌ๋Ÿฌ๋ถ„๋“ค์ด ์›ํ•˜๋Š” ์‹œ๋‚˜๋ฆฌ์˜ค๋ฅผ ๋งŒ๋“ค ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์œ„์˜ ์ฝ”๋“œ๋Š” "/rest/test"๋กœ ์š”์ฒญ์„ ๋ณด๋ƒˆ์„ ๋•Œ, ํ˜„์žฌ ๋ฆฌ์†Œ์Šค ํด๋”์— ์ƒ์„ฑ๋˜์–ด ์žˆ๋Š” test.json์˜ ํŒŒ์ผ์„ ์‘๋‹ตํ•ด์ฃผ๋„๋ก ์‹œ๋‚˜๋ฆฌ์˜ค ๋˜์–ด ์žˆ๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์‹ค์ œ Spring boot์—์„œ๋Š” ์ •์  ๊ฒฝ๋กœ์˜ ์žˆ๋Š” ๋ฆฌ์†Œ์Šค๋ฅผ ์ •์˜ํ•  ์ˆ˜ ์žˆ๋Š”๋ฐ, ์ด์˜ ์ตœ์ƒ์œ„ ๊ฒฝ๋กœ๊ฐ€ ๋ฐ”๋กœ resources์ž…๋‹ˆ๋‹ค.

์ด๋ ‡๊ฒŒ resources ํด๋”์— test.json ํŒŒ์ผ์„ ๋งŒ๋“ค์–ด์ฃผ๋ฉด ๋˜๋Š”๋ฐ, ๋‚ด์šฉ์€ ์•„๋ž˜์™€ ๊ฐ™์ด ์ž…๋ ฅํ•ด์ฃผ์„ธ์š”.

{
  "idx": null,
  "name": "ํ…Œ์ŠคํŠธ",
  "price": 0,
  "date": null
}

์ฝ”๋“œ๋ฅผ ๋ณด๋ฉด, test.json ํŒŒ์ผ์„ ๊ฐ–์˜จ ๋‹ค์Œ, ๊ทธ ๊ฐ’์˜ name ํ•„๋“œ๊ฐ€ "ํ…Œ์ŠคํŠธ" ๊ฐ’์ธ์ง€๋ฅผ ํ™•์ธํ•˜๋Š” ๊ฒƒ์ด๊ธฐ ๋•Œ๋ฌธ์— name ํ•„๋“œ๋ฅผ ์ œ์™ธํ•œ ๋‚˜๋จธ์ง€๋Š” ์ž์œ ๋กญ๊ฒŒ ์ž…๋ ฅํ•˜์…”๋„ ๋ฌด๋ฐฉํ•ฉ๋‹ˆ๋‹ค.

๊ฐ™์€ ๋ฐฉ๋ฒ•์œผ๋กœ andRespond ์•ˆ์— ์‘๋‹ต ์‹œ๋‚˜๋ฆฌ์˜ค๋ฅผ ๋งŒ๋“ค ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค. withServerError ๋ฉ”์†Œ๋“œ๋ฅผ ์ด์šฉํ•˜๋ฉด 500 ์˜ค๋ฅ˜๋ฅผ ์‘๋‹ต ์‹œํ‚ค๋Š” ์‹œ๋‚˜๋ฆฌ์˜ค๋ฅผ ๋งŒ๋“ค์–ด์ฃผ๋Š”๋ฐ, ์ด ๋•Œ ์˜ค๋ฅ˜๋ฅผ ํ•ธ๋“ค๋ง ํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” Junit 5์—์„œ ์ œ๊ณตํ•˜๋Š” assertThrows ๋ฉ”์†Œ๋“œ๋ฅผ ์ด์šฉํ•ด์ค๋‹ˆ๋‹ค.

assertThrows๋Š” ํ•ธ๋“ค๋ง ํ•  ์˜ค๋ฅ˜์™€ ํ•จ๊ป˜ Lambda ํ•จ์ˆ˜์‹์˜ ์ต๋ช… ํ•จ์ˆ˜๋ฅผ ๋„ฃ์–ด, ์š”์ฒญํ•  ์ฝ”๋“œ๋ฅผ ๋„ฃ์œผ๋ฉด ๋˜๋Š”๋ฐ, ๋งŒ์•ฝ ์š”์ฒญํ•œ ์ฝ”๋“œ๊ฐ€ ์—†์œผ๋ฉด ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•˜์ง€ ์•Š์€ ๊ฒƒ์œผ๋กœ ๊ฐ„์ฃผ๋˜๋‹ˆ, ๋ฐ˜๋“œ์‹œ API ์š”์ฒญ ์ฝ”๋“œ๋ฅผ ์‚ฝ์ž…ํ•˜์…”์•ผ ํ•ฉ๋‹ˆ๋‹ค.

 

@JsonTest

๋งˆ์ง€๋ง‰์œผ๋กœ JsonTest๋ฅผ ๋ณด๋„๋ก ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค. JsonTest๋Š” ์œ„์˜ ํ…Œ์ŠคํŠธ์™€๋Š” ์กฐ๊ธˆ ์ฐจ์ด๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ์œ„์˜ ํ…Œ์ŠคํŠธ๋Š” Json์˜ ์‘๋‹ต์„ ๋ฐ›์•„ POJO ๊ฐ์ฒด๋กœ ์ฒ˜๋ฆฌํ•œ ๋’ค, ํ•ด๋‹น ๋ฐ์ดํ„ฐ์˜ ์ •ํ™•์„ฑ์„ ๊ฒ€์ฆํ•˜๋Š” ํ…Œ์ŠคํŠธ ์ฝ”๋“œ์˜€๋‹ค๋ฉด, ์ง€๊ธˆ์€ ์‘๋‹ต์ด ์ •ํ™•ํ•˜๊ฒŒ JSON์œผ๋กœ ์ง๋ ฌํ™” ๋˜์–ด ์ „๋‹ฌ๋˜๋Š”์ง€ ํ™•์ธํ•˜๋Š” ํ…Œ์ŠคํŠธ์ž…๋‹ˆ๋‹ค.

๊ทธ๋ž˜์„œ ํ…Œ์ŠคํŠธ ๊ณผ์ •์€ ์ด ๋‘ ๊ฐ€์ง€๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ๋ฌธ์ž์—ด๋กœ ๋‚˜์—ด ๋œ, JSON ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ์ฒด๋กœ ๋ณ€ํ™˜ํ•˜์—ฌ ๋ณ€ํ™˜๋œ ๊ฐ’์„ ํ…Œ์ŠคํŠธํ•˜๋Š” ๊ฒฝ์šฐ์™€ ๊ทธ ๋ฐ˜๋Œ€์˜ ๊ฒฝ์šฐ์ด์ง€์š”. ์‹ค์ œ Spring boot starter test์—์„œ๋Š” ์ด๋Ÿฌํ•œ ์ง๋ ฌํ™” ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ๋ณ„๋„๋กœ ์‚ฌ์šฉํ•˜๋Š”๋ฐ, ๊ทธ ๋Œ€ํ‘œ์ ์ธ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๊ฐ€ Jackson๊ณผ Google์˜ Gson ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๊ฐ€ ์žˆ๊ณ , ์‹ค์ œ๋กœ Spring boot starter test์—์„œ๋Š” ๋‘ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ๋ชจ๋‘ ํฌํ•จํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

Jackson ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์ด์šฉํ•ด์„œ ์œ„์—์„œ ์˜ฌ๋ฆฐ test.json์„ ํ…Œ์ŠคํŠธ ํ•ด๋ณด๋„๋ก ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค. ๋จผ์ € POJO ๊ฐ์ฒด๋ฅผ ํ•˜๋‚˜ ๋งŒ๋“ค์–ด์„œ, name๋งŒ "ํ…Œ์ŠคํŠธ"๋ผ๋Š” ์ด๋ฆ„์„ ๊ฐ€์ง„ ๊ฒƒ์œผ๋กœ ๋งŒ๋“ค๊ณ  ๋‚˜๋จธ์ง€๋Š” ๋žœ๋คํ•œ ๊ฐ’์„ ์ง‘์–ด๋„ฃ์Šต๋‹ˆ๋‹ค. ์ด ๊ฐ์ฒด๋Š” POJO ๊ฐ์ฒด๋ž‘ ์—ญ์ง๋ ฌํ™”, ์ง๋ ฌํ™”ํ•œ ๋ฐ์ดํ„ฐ์™€ ์ผ์น˜ํ•˜๋Š”์ง€ ๋ณด๊ธฐ ์œ„ํ•œ ํ…Œ์ŠคํŠธ์ž…๋‹ˆ๋‹ค.

๋ฌธ์ž์—ด ํ˜•ํƒœ๋กœ ์—ญ์‹œ name๋งŒ "ํ…Œ์ŠคํŠธ"์ธ JSON ๋ฌธ์ž์—ด์„ ๋งŒ๋“ค์–ด์ฃผ์‹œ๊ณ , ์ด์ œ Jackson ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์ด์šฉํ•ด json ํŒŒ์ผ๊ณผ ๋ฌธ์ž์—ด์„ ์ง๋ ฌํ™”, ์—ญ์ง๋ ฌํ™”ํ•˜์—ฌ ๊ฐ’์ด ๋งž๋Š”์ง€ ํ…Œ์ŠคํŠธํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค.

 

๋งˆ์น˜๋ฉฐ...

๊ธฐ๋ณธ์ ์œผ๋กœ Spring boot ์™ธ์—๋„ Django, Flask, Express ๋“ฑ ๋‹ค์–‘ํ•œ ์›น ํ”„๋ ˆ์ž„์›Œํฌ์—์„œ ์ด๋ค„์งˆ ์ˆ˜ ์žˆ๋Š” ๊ฐœ๋ฐœ์— ๋Œ€ํ•œ ํ…Œ์ŠคํŠธ๋ฅผ ์ง„ํ–‰ํ•ด๋ดค์Šต๋‹ˆ๋‹ค.

์‚ฌ์‹ค Spring์„ ๋‹ค๋ฃจ๋ฉด์„œ ์ข€ ๊นŒ๋‹ค๋กœ์šด ์ ์€ ๋ฒ„์ „์ด ๋‹จ๊ธฐ๊ฐ„์— ๋ฐ”๋€Œ๋ฉด์„œ ๊ธฐ๋Šฅ์ด๋‚˜ ํ•จ์ˆ˜, ์ฝ”๋“œ๋“ค์ด ๋งŽ์ด ๋ฐ”๋€๋‹ˆ๋‹ค. ์‹ค์ œ๋กœ Junit 4๋ฅผ ์“ฐ์‹œ๋Š” ๋ถ„๋“ค๋„ ์žˆ๊ณ , ์ €์ฒ˜๋Ÿผ ๋ฒ„์ „์„ ๋นจ๋ฆฌ ๋ฐ”๊ฟ”ํƒ€๋ฉด์„œ Junit 5๋กœ ์˜ค์‹  ๋ถ„๋“ค๋„ ์žˆ์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค. ํ•œ ๋ฒˆ ์ฏค ํ…Œ์ŠคํŠธ ์ฝ”๋“œ๋ฅผ ์งœ๋ณด์‹  ๋ถ„๋“ค์€ ์•„์‹œ๊ฒ ์ง€๋งŒ ์ฝ”๋“œ๊ฐ€ ๋งŽ์ด ๋‹ค๋ฆ…๋‹ˆ๋‹ค.

๋˜, ์ตœ๊ทผ์—๋Š” Rx๋ผ๋Š” ๊ฒƒ์ด ๋“ฑ์žฅํ•˜๋ฉด์„œ, ๋น„๋™๊ธฐ ์ฒ˜๋ฆฌ์— ๋Œ€ํ•œ ํ…Œ์ŠคํŠธ์ธ WebFlux ํ…Œ์ŠคํŠธ๋„ ์žˆ๋Š”๋ฐ, ์ด ์ดํ›„์˜ ํ…Œ์ŠคํŠธ๋Š” ๊ฐ๊ฐ ํ•œ ๊ฐœ์”ฉ ํฌ์ŠคํŠธ๋ฅผ ์จ๊ฐ€๋ฉด์„œ ํ•œ ๋ฒˆ ์จ๋ณด๋Š” ๊ณผ์ •์„ ์ ์–ด๋ณด๋„๋ก ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค. ์ด๋ฒˆ ํฌ์ŠคํŠธ์—์„œ๋Š” ๊ฐ„๋‹จํ•œ Spring boot ์•ฑ์„ ๊ฐœ๋ฐœํ•˜๋ฉด์„œ ์‚ฌ์šฉํ•˜๋Š” REST, JSON, MVC ๋“ฑ ๊ธฐ๋ณธ์ ์ธ ๊ฒƒ๋งŒ ์‚ดํŽด๋ดค์Šต๋‹ˆ๋‹ค.

๋ฐ˜์‘ํ˜•
TAGS.

Tistory Comments