๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ
๐Ÿ•Š๏ธ ํ”„๋กœ๊ทธ๋ž˜๋จธ์Šค ๋ฐ๋ธŒ์ฝ”์Šค

SpringBoot Part2-1

by hyeon-z 2023. 6. 27.

 

1. ์†Œํ”„ํŠธ์›จ์–ด ํ…Œ์ŠคํŒ…

 

์†Œํ”„ํŠธ์›จ์–ด ์‹œ์Šคํ…œ์ด ์š”๊ตฌ์‚ฌํ•ญ์„ ์ถฉ์กฑํ•˜๊ณ  ์˜ˆ์ƒ๋œ ๋™์ž‘์„ ์ˆ˜ํ–‰ํ•˜๋Š”์ง€ ํ™•์ธํ•˜๊ธฐ ์œ„ํ•œ ๊ณผ์ •์ด๋‹ค.

์†Œํ”„ํŠธ์›จ์–ด ํ…Œ์ŠคํŠธ๋Š” ๊ฐœ๋ฐœ ์ฃผ๊ธฐ์˜ ์ผ๋ถ€๋กœ์„œ, ๋ฒ„๊ทธ๋ฅผ ์ฐพ๊ณ  ์ˆ˜์ •ํ•˜๋ฉฐ, ์†Œํ”„ํŠธ์›จ์–ด์˜ ํ’ˆ์งˆ์„ ํ–ฅ์ƒ์‹œํ‚ค๋Š” ๋ฐ ์ค‘์š”ํ•œ ์—ญํ• ์„ ํ•œ๋‹ค.

๋ชฉํ‘œ๋Š” ์‹ ๋ขฐ์„ฑ ๋†’์€ ์†Œํ”„ํŠธ์›จ์–ด๋ฅผ ์ œ๊ณตํ•˜์—ฌ ์‚ฌ์šฉ์ž์˜ ์š”๊ตฌ์‚ฌํ•ญ์„ ์ถฉ์กฑ์‹œํ‚ค๋Š” ๊ฒƒ์ด๋‹ค.

 

ํ…Œ์ŠคํŒ… ๋ ˆ๋ฒจ

 

๋‹จ์œ„ ํ…Œ์ŠคํŠธ(Unit Testing): ์†Œํ”„ํŠธ์›จ์–ด์˜ ๊ฐ€์žฅ ์ž‘์€ ๋‹จ์œ„์ธ ๋ชจ๋“ˆ ๋˜๋Š” ํ•จ์ˆ˜๋ฅผ ๊ฐœ๋ณ„์ ์œผ๋กœ ํ…Œ์ŠคํŠธํ•˜๋Š” ๊ฒƒ. ์ฃผ๋กœ ํ”„๋กœ๊ทธ๋ž˜๋จธ๊ฐ€ ์ž์ฒด์ ์œผ๋กœ ์ˆ˜ํ–‰ํ•˜๋ฉฐ, ๋ชจ๋“ˆ์˜ ๋…๋ฆฝ์„ฑ์„ ํ™•์ธํ•˜๊ณ  ์˜ˆ์ƒ๋œ ๋™์ž‘์„ ๊ฒ€์ฆํ•œ๋‹ค.

ํ†ตํ•ฉ ํ…Œ์ŠคํŠธ(Integration Testing): ๋‹จ์œ„ ํ…Œ์ŠคํŠธ์—์„œ ๊ฐœ๋ณ„์ ์œผ๋กœ ํ…Œ์ŠคํŠธํ•œ ๋ชจ๋“ˆ๋“ค์„ ํ†ตํ•ฉํ•˜์—ฌ ์ „์ฒด ์‹œ์Šคํ…œ์ด ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ์ƒํ˜ธ์ž‘์šฉํ•˜๋Š”์ง€ ๊ฒ€์ฆํ•˜๋Š” ๊ฒƒ. ๋‹ค์–‘ํ•œ ์ปดํฌ๋„ŒํŠธ ๊ฐ„์˜ ์ƒํ˜ธ์ž‘์šฉ, ์ธํ„ฐํŽ˜์ด์Šค ๋ฌธ์ œ, ๋ฐ์ดํ„ฐ ํ๋ฆ„ ๋“ฑ์„ ํ™•์ธํ•œ๋‹ค.

์‹œ์Šคํ…œ ํ…Œ์ŠคํŠธ(System Testing):  ์™„์ „ํ•œ ์†Œํ”„ํŠธ์›จ์–ด ์‹œ์Šคํ…œ์„ ๋Œ€์ƒ์œผ๋กœ ์ˆ˜ํ–‰๋˜๋Š” ํ…Œ์ŠคํŠธ. ์‹œ์Šคํ…œ์˜ ๊ธฐ๋Šฅ, ์„ฑ๋Šฅ, ์•ˆ์ „์„ฑ, ๋ณด์•ˆ ๋“ฑ ๋‹ค์–‘ํ•œ ์ธก๋ฉด์„ ํ‰๊ฐ€ํ•˜์—ฌ ์‹œ์Šคํ…œ์ด ์š”๊ตฌ์‚ฌํ•ญ์„ ์ถฉ์กฑ์‹œํ‚ค๊ณ  ์˜ˆ์ƒ๋œ ๋™์ž‘์„ ์ˆ˜ํ–‰ํ•˜๋Š”์ง€ ํ™•์ธํ•œ๋‹ค. ์ด ๋‹จ๊ณ„์—์„œ๋Š” ์ฃผ๋กœ ๊ฐœ๋ฐœ์ž, ํ…Œ์ŠคํŠธ ์—”์ง€๋‹ˆ์–ด ๋˜๋Š” QA(Quality Assurance) ํŒ€์ด ์‹œ์Šคํ…œ์„ ํ…Œ์ŠคํŠธํ•˜๋ฉฐ, ์†Œํ”„ํŠธ์›จ์–ด์˜ ํ’ˆ์งˆ์„ ๊ฒ€์ฆํ•˜๊ณ  ๊ฒฐํ•จ์„ ๋ฐœ๊ฒฌํ•˜๊ณ  ์ˆ˜์ •ํ•œ๋‹ค.

์ธ์ˆ˜ ํ…Œ์ŠคํŠธ(Acceptance Testing): ์‚ฌ์šฉ์ž ๋˜๋Š” ๊ณ ๊ฐ์ด ์š”๊ตฌ์‚ฌํ•ญ์„ ์ถฉ์กฑ์‹œํ‚ค๋Š”์ง€ ํ™•์ธํ•˜๊ธฐ ์œ„ํ•ด ์ˆ˜ํ–‰๋˜๋Š” ํ…Œ์ŠคํŠธ. ์‹œ์Šคํ…œ์ด ์‹ค์ œ ํ™˜๊ฒฝ์—์„œ ์ •์ƒ์ ์œผ๋กœ ์ž‘๋™ํ•˜๋Š”์ง€ ํ™•์ธํ•˜๊ณ  ์‚ฌ์šฉ์ž์˜ ์Šน์ธ์„ ๋ฐ›๊ธฐ ์œ„ํ•ด ์ˆ˜ํ–‰ํ•œ๋‹ค. ์ฃผ๋กœ ๊ณ ๊ฐ, ์ตœ์ข… ์‚ฌ์šฉ์ž, ์—”๋“œ ์œ ์ € ๋“ฑ์ด ์‹œ์Šคํ…œ์„ ์‚ฌ์šฉํ•˜์—ฌ ์‹ค์ œ ์—…๋ฌด๋ฅผ ์ˆ˜ํ–‰ํ•˜๋ฉฐ ํ‰๊ฐ€ํ•œ๋‹ค.

 

Testing Pyramid

 

์†Œํ”„ํŠธ์›จ์–ด ํ…Œ์ŠคํŒ…์—์„œ ํ…Œ์ŠคํŠธ์˜ ์ข…๋ฅ˜์™€ ์ˆ˜ํ–‰ ๋น„์œจ์„ ๋‚˜ํƒ€๋‚ด๋Š” ๊ฐœ๋…

https://theqalead.com/topics/testing-pyramid/

ํ”ผ๋ผ๋ฏธ๋“œ์˜ ๊ณ„์ธต์„ ํ†ตํ•ด ์œ„๋กœ ์ด๋™ํ•˜๋ฉด ํ…Œ์ŠคํŠธ ๋ฒ”์œ„๊ฐ€ ์ฆ๊ฐ€ํ•˜๊ณ  ์ž‘์„ฑํ•ด์•ผ ํ•˜๋Š” ํ…Œ์ŠคํŠธ ์ˆ˜๊ฐ€ ๊ฐ์†Œํ•œ๋‹ค.


2. ๋‹จ์œ„ ํ…Œ์ŠคํŠธ (Unit Test)

 

๋‹จ์œ„ํ…Œ์ŠคํŠธ๋ž€?

https://dancerscode.com/posts/unit-tests/

๋ณ€์ˆ˜๋ฅผ ์„ค์ •ํ•˜๊ณ  ๋ฉ”์„œ๋“œ๋ฅผ ํ†ตํ•ด return value๋ฅผ ํ™•์ธํ•˜์—ฌ ์˜ˆ์ƒํ•œ๋Œ€๋กœ ๋™์ž‘ํ•˜์˜€๋Š”์ง€ ํ™•์ธํ•œ๋‹ค.

 

๐Ÿ’ก SUT (System Under Test) 

ํ…Œ์ŠคํŠธ์˜ ๋Œ€์ƒ์ด ๋˜๋Š” ์‹œ์Šคํ…œ ๋˜๋Š” ์†Œํ”„ํŠธ์›จ์–ด ๊ตฌ์„ฑ ์š”์†Œ, ๋…๋ฆฝ์ ์œผ๋กœ ํ…Œ์ŠคํŠธ๋  ์ˆ˜ ์žˆ๋Š” ์ตœ์†Œํ•œ์˜ ๊ธฐ๋Šฅ ๋‹จ์œ„ (๋ณดํ†ต class)

๋‹จ์œ„ํ…Œ์ŠคํŠธ๋ฅผ ์ˆ˜ํ–‰ํ•  ๋•Œ๋Š” SUT๋ฅผ ์ •ํ™•ํ•˜๊ฒŒ ๋ถ„๋ฆฌํ•˜๊ณ , ๊ทธ ์ฝ”๋“œ๋‚˜ ๊ธฐ๋Šฅ์— ๋Œ€ํ•œ ํ…Œ์ŠคํŠธ๋ฅผ ์ง„ํ–‰ํ•œ๋‹ค.

SUT๊ฐ€ ๋…๋ฆฝ์ ์œผ๋กœ ํ…Œ์ŠคํŠธ๋จ์œผ๋กœ์จ ํ•ด๋‹น ์ฝ”๋“œ์˜ ๋™์ž‘๊ณผ ์ •ํ™•์„ฑ์„ ํ™•์ธํ•˜๊ณ  ๊ฒ€์ฆํ•  ์ˆ˜ ์žˆ๋‹ค.

์ด๋ฅผ ํ†ตํ•ด ๊ฐœ๋ฐœ์ž๋Š” ์ž‘์€ ๋‹จ์œ„์˜ ์ฝ”๋“œ๋ฅผ ๊ฒฌ๊ณ ํ•˜๊ฒŒ ๋งŒ๋“ค๊ณ , ์ „์ฒด ์‹œ์Šคํ…œ์˜ ์•ˆ์ •์„ฑ๊ณผ ์‹ ๋ขฐ์„ฑ์„ ํ–ฅ์ƒ์‹œํ‚ฌ ์ˆ˜ ์žˆ๋‹ค.

 

๋‹จ์œ„ํ…Œ์ŠคํŠธ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ์ด์œ 

 

๊ฒฐํ•จ ์‹๋ณ„: ๋‹จ์œ„ ํ…Œ์ŠคํŠธ๋Š” ์ฝ”๋“œ์˜ ์ž‘์€ ๋ถ€๋ถ„์„ ํ…Œ์ŠคํŠธํ•˜๋ฏ€๋กœ ๊ฒฐํ•จ์„ ์‹๋ณ„ํ•˜๊ธฐ์— ์šฉ์ดํ•˜๋‹ค. ํŠน์ • ํ•จ์ˆ˜ ๋˜๋Š” ๋ชจ๋“ˆ์—์„œ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•˜๋ฉด ํ•ด๋‹น ๋‹จ์œ„ ํ…Œ์ŠคํŠธ๋ฅผ ํ†ตํ•ด ๊ฒฐํ•จ์„ ์‰ฝ๊ฒŒ ์ถ”์ ํ•˜๊ณ  ์ˆ˜์ •ํ•  ์ˆ˜ ์žˆ๋‹ค.

 

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

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

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

๊ฐœ๋ฐœ ์ƒ์‚ฐ์„ฑ ํ–ฅ์ƒ: ํ…Œ์ŠคํŠธ ์ฃผ๋„ ๊ฐœ๋ฐœ(Test-Driven Development, TDD) ๋ฐฉ๋ฒ•๋ก ์„ ์‚ฌ์šฉํ•˜๋ฉด ํ…Œ์ŠคํŠธ๋ฅผ ๋จผ์ € ์ž‘์„ฑํ•˜๊ณ  ๊ทธ์— ๋งž๊ฒŒ ์ฝ”๋“œ๋ฅผ ๊ฐœ๋ฐœํ•˜๋Š” ๋ฐฉ์‹์œผ๋กœ ๊ฐœ๋ฐœ ์ƒ์‚ฐ์„ฑ์„ ๋†’์ผ ์ˆ˜ ์žˆ๋‹ค. ๋˜ํ•œ, ๋‹จ์œ„ ํ…Œ์ŠคํŠธ๋Š” ๋ฒ„๊ทธ๋ฅผ ๋ฏธ๋ฆฌ ๋ฐœ๊ฒฌํ•˜์—ฌ ๋””๋ฒ„๊น… ์‹œ๊ฐ„์„ ์ค„์ด๊ณ  ์•ˆ์ •์ ์ธ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•˜๋Š” ๋ฐ ๋„์›€์ด ๋œ๋‹ค.

 

ํ…Œ์ŠคํŠธ ๋”๋ธ”

 

์†Œํ”„ํŠธ์›จ์–ด ํ…Œ์ŠคํŠธ์—์„œ ์‹ค์ œ ์˜์กด์„ฑ์„ ๋Œ€์ฒดํ•˜๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉ๋˜๋Š” ๊ฐ์ฒด

์‹ค์ œ ์˜์กด์„ฑ์ด ํ…Œ์ŠคํŠธ์— ์–ด๋ ค์›€์„ ์ค„ ์ˆ˜ ์žˆ๋Š” ๊ฒฝ์šฐ, ํ…Œ์ŠคํŠธ ๋”๋ธ”์„ ์‚ฌ์šฉํ•˜์—ฌ ์˜์กด์„ฑ์„ ๋Œ€์ฒดํ•˜๊ณ  ํ…Œ์ŠคํŠธ์˜ ๊ฒฉ๋ฆฌ์„ฑ๊ณผ ์ œ์–ด ๊ฐ€๋Šฅ์„ฑ์„ ํ–ฅ์ƒ์‹œํ‚ฌ ์ˆ˜ ์žˆ๋‹ค.

 

๐Ÿ‘† Dummy

- ๊ฐ€์žฅ ๊ธฐ๋ณธ์ ์ธ ํ…Œ์ŠคํŠธ ๋”๋ธ”

- ์ธ์Šคํ„ด์Šคํ™”๋œ ๊ฐ์ฒด๊ฐ€ ํ•„์š”ํ•˜์ง€๋งŒ ๊ธฐ๋Šฅ์€ ํ•„์š”ํ•˜์ง€ ์•Š์€ ๊ฒฝ์šฐ์— ์‚ฌ์šฉํ•œ๋‹ค.
- Dummy ๊ฐ์ฒด์˜ ๋ฉ”์„œ๋“œ๊ฐ€ ํ˜ธ์ถœ๋˜์—ˆ์„ ๋•Œ ์ •์ƒ ๋™์ž‘์€ ๋ณด์žฅํ•˜์ง€ ์•Š๋Š”๋‹ค.
- ๊ฐ์ฒด๋Š” ์ „๋‹ฌ๋˜์ง€๋งŒ ์‚ฌ์šฉ๋˜์ง€ ์•Š๋Š” ๊ฐ์ฒด์ด๋‹ค.
- ์ฃผ๋กœ ํ…Œ์ŠคํŠธ ์‹œ์— ํ•„์š”ํ•œ ํ˜‘๋ ฅ ๊ฐ์ฒด(Collaborator)๋กœ์„œ ์‚ฌ์šฉ๋œ๋‹ค.

 

๐Ÿ‘† Fake

- ์‹ค์ œ ๊ตฌํ˜„๊ณผ ์œ ์‚ฌํ•œ ๋™์ž‘์„ ๊ฐ–๋Š” ๋‹จ์ˆœํ•œ ๊ตฌํ˜„์ฒด

- ์‹ค์ œ ์˜์กด์„ฑ์„ ๋Œ€์ฒดํ•˜๋Š” ๋ฐ ์‚ฌ์šฉ๋˜๋ฉฐ, ์‹ค์ œ ์˜์กด์„ฑ๊ณผ ์œ ์‚ฌํ•œ ๋™์ž‘์„ ์ˆ˜ํ–‰ํ•˜์ง€๋งŒ ๋‹จ์ˆœํ•˜๊ฒŒ ๊ตฌํ˜„๋˜์–ด ์žˆ๋‹ค.

 

๐Ÿ‘† Stub

- ํ…Œ์ŠคํŠธ ์ค‘์— ํ˜ธ์ถœ๋  ๋•Œ ๋ฏธ๋ฆฌ ์ •์˜๋œ ์‘๋‹ต์„ ๋ฐ˜ํ™˜ํ•˜๋Š” ๊ฐ์ฒด์ž…๋‹ˆ๋‹ค.

- ์‹ค์ œ ๋™์ž‘์„ ๊ตฌํ˜„ํ•˜์ง€ ์•Š๊ณ  ๋‹จ์ˆœํžˆ ์ •ํ•ด์ง„ ๊ฐ’์„ ๋ฐ˜ํ™˜ํ•˜์—ฌ ์›ํ•˜๋Š” ์ƒํ™ฉ์„ ์‹œ๋ฎฌ๋ ˆ์ด์…˜ํ•œ๋‹ค.

 

๐Ÿ‘† Spy

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

 

๐Ÿ‘† Mock

- ํ˜ธ์ถœ์— ๋Œ€ํ•œ ๊ธฐ๋Œ€๋ฅผ ๋ช…์„ธํ•˜๊ณ  ๋‚ด์šฉ์— ๋”ฐ๋ผ ๋™์ž‘ํ•˜๋„๋ก ํ”„๋กœ๊ทธ๋ž˜๋ฐ๋œ ๊ฐ์ฒด์ด๋‹ค.


3. ํ†ตํ•ฉํ…Œ์ŠคํŠธ

 

Unit Testing Principles, Practices, and Patterns

๋‹ค๋ฅธ ์˜์กด๊ด€๊ณ„์™€ ์—ฐ๋™์ด ์ž˜ ๋˜๋Š”์ง€ ํ…Œ์ŠคํŠธํ•˜๋Š” ๋ฐ ์‚ฌ์šฉ๋œ๋‹ค.


4. JUnit

 

์ž๋ฐ” ์–ธ์–ด๋ฅผ ์œ„ํ•œ ์œ ๋‹› ํ…Œ์ŠคํŒ… ํ”„๋ ˆ์ž„์›Œํฌ

 

JUnit์˜ ๊ธฐ๋Šฅ

 

- ๋งค ๋‹จ์œ„ ํ…Œ์ŠคํŠธ์‹œ๋งˆ๋‹ค ํ…Œ์ŠคํŠธ ํด๋ž˜์Šค์˜ ์ธ์Šคํ„ด์Šค๊ฐ€ ์ƒ์„ฑ๋˜์–ด ๋…๋ฆฝ์ ์ธ ํ…Œ์ŠคํŠธ๊ฐ€ ๊ฐ€๋Šฅํ•˜๋‹ค.

-> ์ด์ „ ํ…Œ์ŠคํŠธ๊ฐ€ ๋‹ค์Œ ํ…Œ์ŠคํŠธ์— ์˜ํ–ฅ์„ ์ฃผ์ง€ ์•Š์Œ

- ์• ๋…ธํ…Œ์ด์…˜์„ ์ œ๊ณตํ•ด์„œ ํ…Œ์ŠคํŠธ ๋ผ์ดํ”„ ์‚ฌ์ดํด์„ ๊ด€๋ฆฌํ•˜๊ฒŒ ํ•ด ์ฃผ๊ณ  ํ…Œ์ŠคํŠธ ์ฝ”๋“œ๋ฅผ ๊ฐ„๊ฒฐํ•˜๊ฒŒ ์ž‘์„ฑํ•˜๋„๋ก ์ง€์›ํ•œ๋‹ค. (ex. @BeforeEach, @AfterEach)

- ํ…Œ์ŠคํŠธ ๋Ÿฌ๋„ˆ๋ฅผ ์ œ๊ณตํ•ด์„œ ์ธํ…”๋ฆฌ์ œ์ด / ์ดํด๋ฆฝ์Šค / ๋ฉ”์ด๋ธ ๋“ฑ์—์„œ ํ…Œ์ŠคํŠธ ์ฝ”๋“œ๋ฅผ ์‰ฝ๊ฒŒ ์‹คํ–‰ํ•˜๊ฒŒ ํ•œ๋‹ค.

- assert๋กœ ํ…Œ์ŠคํŠธ ์ผ€์ด์Šค์˜ ์ˆ˜ํ–‰ ๊ฒฐ๊ณผ๋ฅผ ํŒ๋ณ„ํ•œ๋‹ค. (ex. assertEquals(์˜ˆ์ƒ ๊ฐ’, ์‹ค์ œ ๊ฐ’))

- ๊ฒฐ๊ณผ๋Š” ์„ฑ๊ณต(๋…น์ƒ‰), ์‹คํŒจ(๋ถ‰์€์ƒ‰) ์ค‘ ํ•˜๋‚˜๋กœ ํ‘œ์‹œํ•œ๋‹ค.

 

Junit 4

 

junit.jar๋ผ๋Š” ๋‹จ์ผ jarํŒŒ์ผ๋กœ ๋ฐฐํฌ๋˜์—ˆ๋‹ค.

๋‹จ์ : ํ™•์žฅ์„ฑ์ด ๋–จ์–ด์ง„๋‹ค.

 

Junit5

 

3๊ฐœ์˜ ๋ชจ๋“ˆ๋กœ ๋ถ„๋ฆฌ๋˜์—ˆ๋‹ค.

 

 

 

๐Ÿ‘† JUnit Platform


- JVM ์ƒ์— ํ…Œ์ŠคํŒ… ํ”„๋ ˆ์ž„์›Œํฌ๋ฅผ ์‹คํ–‰ํ•˜๊ธฐ ์œ„ํ•œ ๊ธฐ๋ฐ˜์„ ์ œ๊ณตํ•œ๋‹ค.

- TestEngine ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ํ†ตํ•ด ํ…Œ์ŠคํŠธ๋ฅผ ๋ฐœ๊ฒฌํ•˜๊ณ  ํ…Œ์ŠคํŠธ ๊ณ„ํš์„ ์ƒ์„ฑํ•˜๋ฉฐ, ์ด๋ฅผ ํ†ตํ•ด ํ…Œ์ŠคํŠธ๋ฅผ ์‹คํ–‰ํ•˜๊ณ  ๊ฒฐ๊ณผ๋ฅผ ๋ณด๊ณ ํ•œ๋‹ค.

- ๋‹ค์–‘ํ•œ ํ…Œ์ŠคํŠธ ์—”์ง„๊ณผ์˜ ํ†ตํ•ฉ์„ ์ง€์›ํ•˜๋ฉฐ, ํ…Œ์ŠคํŠธ ํ”„๋ ˆ์ž„์›Œํฌ์—์„œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ์ผ๊ด€๋œ ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ์ œ๊ณตํ•œ๋‹ค. ์ด๋ฅผ ํ†ตํ•ด ํ…Œ์ŠคํŠธ ํ™˜๊ฒฝ์— ์ƒ๊ด€์—†์ด JUnit ํ…Œ์ŠคํŠธ๋ฅผ ์‹คํ–‰ํ•˜๊ณ  ํ†ตํ•ฉํ•  ์ˆ˜ ์žˆ๋‹ค.

 

+) TestEngine์ธํ„ฐํŽ˜์ด์Šค:  JUnit Platform์—์„œ ํ…Œ์ŠคํŠธ๋ฅผ ๋ฐœ๊ฒฌํ•˜๊ณ  ์‹คํ–‰ํ•˜๋Š” ์—ญํ• ์„ ๋‹ด๋‹นํ•˜๋Š” ์ธํ„ฐํŽ˜์ด์Šค. ์ด ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๊ตฌํ˜„ํ•จ์œผ๋กœ์จ ํŠน์ •ํ•œ ํ…Œ์ŠคํŠธ ์—”์ง„๊ณผ JUnit Platform์„ ํ†ตํ•ฉํ•  ์ˆ˜ ์žˆ๋‹ค.


๐Ÿ‘† JUnit Jupiter


- TestEngine์˜ ์‹ค์ œ ๊ตฌํ˜„์ฒด ์ค‘ ํ•˜๋‚˜

-  JUnit 5์˜ ์ฃผ์š” ๊ธฐ๋Šฅ์„ ์ œ๊ณตํ•˜๋Š” ๋ชจ๋“ˆ

- jupiter-api๋ฅผ ์‚ฌ์šฉํ•ด์„œ ์ž‘์„ฑํ•œ ํ…Œ์ŠคํŠธ ์ฝ”๋“œ๋ฅผ ๋ฐœ๊ฒฌํ•˜๊ณ  ์‹คํ–‰ํ•œ๋‹ค.

- ์• ๋„ˆํ…Œ์ด์…˜ ๊ธฐ๋ฐ˜์˜ ํ…Œ์ŠคํŠธ ์ž‘์„ฑ์„ ์ง€์›ํ•œ๋‹ค. (ex. @Test, @BeforeEach, @AfterEach)

 

+) Jupiter API: JUnit 5์—์„œ ์‚ฌ์šฉ๋˜๋Š” ํ…Œ์ŠคํŠธ ์ž‘์„ฑ์„ ์œ„ํ•œ API์ด๋‹ค. JUnit Jupiter ๋ชจ๋“ˆ์—์„œ ์ œ๊ณต๋˜๋ฉฐ, ํ…Œ์ŠคํŠธ ํด๋ž˜์Šค, ํ…Œ์ŠคํŠธ ๋ฉ”์„œ๋“œ, ์–ด์„ค์…˜ ๋“ฑ์„ ์ •์˜ํ•˜๋Š” ๋ฐ ์‚ฌ์šฉ๋œ๋‹ค.


๐Ÿ‘†JUnit Vintage

 

- ์ด์ „ ๋ฒ„์ „์˜ JUnit ํ…Œ์ŠคํŠธ๋ฅผ JUnit 5 ํ”Œ๋žซํผ์—์„œ ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ๋„๋ก ์ง€์›ํ•˜๋Š” ๋ชจ๋“ˆ

- JUnit 3 ๋ฐ JUnit 4๋กœ ์ž‘์„ฑ๋œ ๊ธฐ์กด์˜ ํ…Œ์ŠคํŠธ๋ฅผ JUnit 5 ํ”Œ๋žซํผ์—์„œ ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ๋„๋ก ๋ธŒ๋ฆฌ์ง€ ์—ญํ• ์„ ์ˆ˜ํ–‰ํ•œ๋‹ค. ์ด๋ฅผ ํ†ตํ•ด ๊ธฐ์กด์˜ ํ…Œ์ŠคํŠธ ์ฝ”๋“œ๋ฅผ JUnit 5๋กœ ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ ํ•˜๋ฉด์„œ๋„ ํ˜ธํ™˜์„ฑ์„ ์œ ์ง€ํ•  ์ˆ˜ ์žˆ๋‹ค.

- ๊ธฐ์กด์— JUnit 4 ๋ฒ„์ „์œผ๋กœ ์ž‘์„ฑํ•œ ํ…Œ์ŠคํŠธ ์ฝ”๋“œ๋ฅผ ์‹คํ–‰ํ•  ๋•Œ์—๋Š” vintage-engine ๋ชจ๋“ˆ์„ ์‚ฌ์šฉํ•œ๋‹ค.


5. Junit5 ์‹ค์Šต

 

ํ…Œ์ŠคํŠธ ํด๋ž˜์Šค์˜ ๋ฉ”์„œ๋“œ๋Š” return ํƒ€์ž…์ด ํ•ญ์ƒ void๋‹ค.

 

๋‹ค์–‘ํ•œ Junit5 Annotation

 

@Test: ํ…Œ์ŠคํŠธ ๋ฉ”์„œ๋“œ์— ๋ถ™์—ฌ์„œ ํ•ด๋‹น ๋ฉ”์„œ๋“œ๊ฐ€ ํ…Œ์ŠคํŠธ ๋ฉ”์„œ๋“œ์ž„์„ ํ‘œ์‹œํ•ฉ๋‹ˆ๋‹ค.

@DisplayName: ํ…Œ์ŠคํŠธ ํด๋ž˜์Šค ๋˜๋Š” ํ…Œ์ŠคํŠธ ๋ฉ”์„œ๋“œ์— ์‚ฌ์šฉํ•˜์—ฌ ํ•ด๋‹น ํ…Œ์ŠคํŠธ์˜ ์ด๋ฆ„์„ ์ง€์ •ํ•˜๋Š” ๋ฐ ์‚ฌ์šฉ๋œ๋‹ค.

@Disabled: ํ•ด๋‹น ํ…Œ์ŠคํŠธ๋ฅผ ๋น„ํ™œ์„ฑํ™”ํ•˜์—ฌ ์‹คํ–‰๋˜์ง€ ์•Š๋„๋ก ํ•œ๋‹ค.

@BeforeAll: ํ…Œ์ŠคํŠธ ํด๋ž˜์Šค ๋‚ด์—์„œ ๋ชจ๋“  ํ…Œ์ŠคํŠธ ๋ฉ”์„œ๋“œ๊ฐ€ ์‹คํ–‰๋˜๊ธฐ ์ด์ „์— ๋”ฑ ํ•œ ๋ฒˆ ํ˜ธ์ถœ๋˜๋Š” ๋ฉ”์„œ๋“œ๋ฅผ ์ง€์ •ํ•˜๋Š” ๋ฐ ์‚ฌ์šฉ๋œ๋‹ค. ํ…Œ์ŠคํŠธ ์ „์— ํ•„์š”ํ•œ ์„ค์ • ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•  ๋•Œ ์‚ฌ์šฉ๋œ๋‹ค.

-> ํ•ด๋‹น ๋ฉ”์„œ๋“œ๋Š” static์œผ๋กœ ์„ ์–ธ๋˜์–ด์•ผ ํ•˜๋ฉฐ ์–ด๋–ค ๋ฆฌํ„ด ๊ฐ’๋„ ๊ฐ€์ ธ์„œ๋Š” ์•ˆ ๋œ๋‹ค.

-> ํ…Œ์ŠคํŠธ ํด๋ž˜์Šค๊ฐ€ ์ธ์Šคํ„ด์Šคํ™”๋˜๊ธฐ ์ด์ „์— ์‹คํ–‰ํ•ด์•ผ ๋˜๊ธฐ ๋•Œ๋ฌธ (static)

@BeforeEach: ๊ฐ๊ฐ์˜ ํ…Œ์ŠคํŠธ ๋ฉ”์„œ๋“œ๊ฐ€ ์‹คํ–‰๋˜๊ธฐ ์ „์— ์‹คํ–‰๋˜์–ด์•ผ ํ•˜๋Š” ์„ค์ •์ด๋‚˜ ์ดˆ๊ธฐํ™” ์ž‘์—…์„ ์ •์˜ํ•  ๋•Œ ์‚ฌ์šฉ๋œ๋‹ค.

@AssertAll์—ฌ๋Ÿฌ ๊ฐœ์˜ ๋‹จ์–ธ๋ฌธ(assertion)์„ ๊ทธ๋ฃนํ™”ํ•˜์—ฌ ๋ชจ๋‘ ์‹คํ–‰ํ•˜๊ณ  ๊ทธ ๊ฒฐ๊ณผ๋ฅผ ํ•œ ๋ฒˆ์— ํ™•์ธํ•˜๋Š” ๊ธฐ๋Šฅ์„ ์ œ๊ณตํ•œ๋‹ค.

 

+) ํ•ด๋‹น ๋‚ด์šฉ์„ ๋” ์•Œ๊ณ  ์‹ถ๋‹ค๋ฉด ํ•˜๋‹จ ๋งํฌ ์ฐธ๊ณ 

JUnit Class Assertions

JUnit Test Annotations

 

JUnit Jupiter, Hamcrest

 

๐Ÿ‘† junit.jupiter.api.assertion

 

- JUnit Jupiter์—์„œ ์ œ๊ณตํ•˜๋Š” ์–ด์„ค์…˜(assertion) ๊ธฐ๋Šฅ์„ ๋‹ด๋‹นํ•˜๋Š” ํŒจํ‚ค์ง€
- ๋‹ค์–‘ํ•œ ์–ด์„ค์…˜(assertion) ๋ฉ”์„œ๋“œ๋ฅผ ์ œ๊ณตํ•˜์—ฌ ํ…Œ์ŠคํŠธ ์ฝ”๋“œ์—์„œ ์˜ˆ์ƒ ๊ฒฐ๊ณผ์™€ ์‹ค์ œ ๊ฒฐ๊ณผ๋ฅผ ๋น„๊ตํ•˜๊ณ  ๊ฒ€์ฆํ•  ์ˆ˜ ์žˆ๋‹ค.

- ex)  assertEquals(), assertTrue(), assertNotNull() 

assertEquals(2, 1 + 1);

 

๐Ÿ‘†org.hamcrest.matcher

 

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

- ์ปฌ๋ ‰์…˜์˜ ์š”์†Œ ํฌํ•จ ์—ฌ๋ถ€, ๋ฌธ์ž์—ด ํŒจํ„ด ์ผ์น˜ ๋“ฑ ๋‹ค์–‘ํ•œ ๋น„๊ต์™€ ์กฐ๊ฑด์„ ํ‘œํ˜„ํ•  ์ˆ˜ ์žˆ๋‹ค.

- ex) equalTo(), containsString(), greaterThan() 

assertThat(1 + 1, equalTo(2));

6. Mock Object (๋ชจ์˜ ๊ฐ์ฒด)

 

https://devfoxstar.github.io/test/test-double/

 

๐Ÿ‘† Mock, Spy

- ํ–‰์œ„ ๊ฒ€์ฆ(behavior verification)

- ๋ฉ”์„œ๋“œ์˜ ๋ฆฌํ„ด ๊ฐ’์œผ๋กœ ํŒ๋‹จํ•  ์ˆ˜ ์—†๋Š” ๊ฒฝ์šฐ, ํŠน์ • ๋™์ž‘์„ ์ˆ˜ํ–‰ํ•˜๋Š”์ง€ ํ™•์ธํ•œ๋‹ค.

- ํŠน์ • ๋ฉ”์„œ๋“œ๊ฐ€ ํ˜ธ์ถœ๋˜์—ˆ๋Š”์ง€, ํ˜ธ์ถœ๋œ ํšŸ์ˆ˜๊ฐ€ ์˜ฌ๋ฐ”๋ฅธ์ง€, ๋งค๊ฐœ๋ณ€์ˆ˜๊ฐ€ ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ์ „๋‹ฌ๋˜์—ˆ๋Š”์ง€ ๋“ฑ์„ ๊ฒ€์ฆํ•˜๋Š” ๋ฐ ์‚ฌ์šฉ๋œ๋‹ค.

 

๐Ÿ‘† Stub, dummy, fake

- ์ƒํƒœ ๊ฒ€์ฆ(state verification)

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

 

Mock Object ์ƒ์„ฑ์„ ๋„์™€์ฃผ๋Š” Test Framework 

 

- Mockito

- JMock

- EasyMock


7.  Spring Test

 

์Šคํ”„๋ง ํ”„๋ ˆ์ž„์›Œํฌ์—์„œ ์ œ๊ณตํ•˜๋Š” ํ…Œ์ŠคํŠธ ์ง€์› ๊ธฐ๋Šฅ์„ ๋‹ด๊ณ  ์žˆ๋Š” ๋ชจ๋“ˆ

์Šคํ”„๋ง ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ํ…Œ์ŠคํŠธํ•˜๋Š” ๋ฐ ํ•„์š”ํ•œ ๋‹ค์–‘ํ•œ ๊ธฐ๋Šฅ๊ณผ ์œ ํ‹ธ๋ฆฌํ‹ฐ๋ฅผ ์ œ๊ณตํ•˜์—ฌ ๊ฐœ๋ฐœ์ž๊ฐ€ ํšจ๊ณผ์ ์œผ๋กœ ํ…Œ์ŠคํŠธ๋ฅผ ์ž‘์„ฑํ•˜๊ณ  ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ๋„๋ก ๋„์™€์ค€๋‹ค.

 

- ์Šคํ”„๋ง ํ…Œ์ŠคํŠธ ์ปจํ…์ŠคํŠธ(TestContext) ๊ด€๋ฆฌ: ํ…Œ์ŠคํŠธ ์‹คํ–‰ ์‹œ ์Šคํ”„๋ง ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์ปจํ…์ŠคํŠธ๋ฅผ ๋กœ๋”ฉํ•˜๊ณ  ๊ด€๋ฆฌํ•œ๋‹ค. ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์ปจํ…์ŠคํŠธ๋ฅผ ํ…Œ์ŠคํŠธ์—์„œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ, ํ…Œ์ŠคํŠธ์šฉ ๋นˆ ์ฃผ์ž… ๋ฐ ํ…Œ์ŠคํŠธ ํ™˜๊ฒฝ ์„ค์ • ๋“ฑ์„ ์ง€์›ํ•œ๋‹ค.

- ํ…Œ์ŠคํŠธ์šฉ ์• ๋„ˆํ…Œ์ด์…˜ ์ง€์›: @RunWith, @ContextConfiguration, @Transactional, @WebAppConfiguration ๋“ฑ์˜ ์• ๋„ˆํ…Œ์ด์…˜์„ ์‚ฌ์šฉํ•˜์—ฌ ํ…Œ์ŠคํŠธ๋ฅผ ์„ค์ •ํ•˜๊ณ  ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ๋‹ค.

- ์Šคํ”„๋ง MVC ํ…Œ์ŠคํŠธ: ์Šคํ”„๋ง MVC ์ปจํŠธ๋กค๋Ÿฌ์˜ ํ…Œ์ŠคํŠธ๋ฅผ ์ง€์›ํ•œ๋‹ค. MockMvc๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ HTTP ์š”์ฒญ์„ ๋ชจ์˜(mock)ํ•˜๊ณ  ์‘๋‹ต์„ ๊ฒ€์ฆํ•  ์ˆ˜ ์žˆ๋‹ค.

- ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ํ…Œ์ŠคํŠธ: ํ…Œ์ŠคํŠธ์šฉ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์„ค์ • ๋ฐ ํŠธ๋žœ์žญ์…˜ ๊ด€๋ฆฌ๋ฅผ ์ง€์›ํ•˜์—ฌ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ํ…Œ์ŠคํŠธ๋ฅผ ๊ฐ„ํŽธํ•˜๊ฒŒ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ๋‹ค. ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ํ…Œ์ŠคํŠธ์—์„œ ๋กค๋ฐฑ์ด๋‚˜ ์ปค๋ฐ‹์„ ์ž๋™์œผ๋กœ ์ฒ˜๋ฆฌํ•œ๋‹ค.

- ํ…Œ์ŠคํŠธ ๋ณด์กฐ ์œ ํ‹ธ๋ฆฌํ‹ฐ: ํ…Œ์ŠคํŠธ๋ฅผ ์œ„ํ•œ ๋‹ค์–‘ํ•œ ์œ ํ‹ธ๋ฆฌํ‹ฐ ํด๋ž˜์Šค์™€ ์–ด๋…ธํ…Œ์ด์…˜์„ ์ œ๊ณตํ•œ๋‹ค.

์˜ˆ๋ฅผ ๋“ค์–ด, TestPropertySource, @DirtiesContext, @Repeat, @Timeout ๋“ฑ์˜ ์œ ํ‹ธ๋ฆฌํ‹ฐ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ํ…Œ์ŠคํŠธ ํ™˜๊ฒฝ์„ ์กฐ์ž‘ํ•˜๊ฑฐ๋‚˜ ํ…Œ์ŠคํŠธ ์‹คํ–‰ ์‹œ๊ฐ„์„ ์ œ์–ดํ•  ์ˆ˜ ์žˆ๋‹ค.

 

 

Reference

Test Double์„ ์•Œ์•„๋ณด์ž - Tecoble

 

 

'๐Ÿ•Š๏ธ ํ”„๋กœ๊ทธ๋ž˜๋จธ์Šค ๋ฐ๋ธŒ์ฝ”์Šค' ์นดํ…Œ๊ณ ๋ฆฌ์˜ ๋‹ค๋ฅธ ๊ธ€

SpringBoot Part 3-1  (0) 2023.07.06
SpringBoot Part2-2  (0) 2023.07.03
SpringBoot Part1-5  (0) 2023.06.26
SpringBoot Part1-4  (0) 2023.06.23
SpringBoot Part1-3  (0) 2023.06.22

๋Œ“๊ธ€