๐Ÿ’ป Knowledge/ํ…Œ์ŠคํŠธ์ฝ”๋“œ 7

deleteAllInBatch() vs deleteAll() ๋ฉ”์„œ๋“œ์˜ ์ฐจ์ด

์ƒํ’ˆ(product)๊ณผ ์ฃผ๋ฌธ(order), ๊ทธ๋ฆฌ๊ณ  ์ด ๋‘ ํ…Œ์ด๋ธ” ๊ฐ„ ์—ฐ๊ฒฐ ํ…Œ์ด๋ธ”์ธ orderProduct๊ฐ€ ์žˆ๋‹ค๊ณ  ํ•˜์ž. `deleteAllInBatch()` ๋ฉ”์„œ๋“œ๋กœ ๋ฆฌ์†Œ์Šค๋ฅผ ์ •๋ฆฌํ•˜๋Š” ๊ฒƒ๊ณผ `deleteAll()` ๋ฉ”์„œ๋“œ๋กœ ๋ฆฌ์†Œ์Šค๋ฅผ ์ •๋ฆฌํ•˜๋Š” ๊ฒƒ์˜ ์ฐจ์ด๋ฅผ ์•Œ์•„๋ณด์ž. deleteAllInBatch()๋จผ์ € `deleteAllInBatch()` ๋ฉ”์„œ๋“œ๋ฅผ ์‚ฌ์šฉํ•ด ์ •๋ฆฌํ•ด๋ณผ ๊ฒƒ์ด๋‹ค.@AfterEachvoid tearDown() { orderProductRepository.deleteAllInBatch(); productRepository.deleteAllInBatch(); orderRepository.deleteAllInBatch();} ์œ„ ํ…Œ์ŠคํŠธ์ฝ”๋“œ ์‹คํ–‰ ์‹œ ๋ฐœ์ƒํ•˜๋Š” ์ฟผ๋ฆฌ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.Hiber..

๋” ๋‚˜์€ ํ…Œ์ŠคํŠธ๋ฅผ ์ž‘์„ฑํ•˜๊ธฐ ์œ„ํ•œ ๊ตฌ์ฒด์  ์กฐ์–ธ + ๋‚˜์˜ ์ƒ๊ฐ

ํ…Œ์ŠคํŠธ ํ™˜๊ฒฝ์˜ ๋…๋ฆฝ์„ฑ์„ ๋ณด์žฅํ•˜์ž์•„๋ž˜์™€ ๊ฐ™์€ ํ…Œ์ŠคํŠธ ์ฝ”๋“œ๊ฐ€ ์žˆ๋‹ค๊ณ  ์ƒ๊ฐํ•˜์ž.@DisplayName("์žฌ๊ณ ๊ฐ€ ๋ถ€์กฑํ•œ ์ƒํ’ˆ์œผ๋กœ ์ฃผ๋ฌธ์„ ์ƒ์„ฑํ•˜๋ ค๋Š” ๊ฒฝ์šฐ ์˜ˆ์™ธ๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค.")@Testvoid createOrderWithNoStock() { // given LocalDateTime registeredDateTime = LocalDateTime.now(); Product product1 = createProduct(BOTTLE, "001", 1000); Product product2 = createProduct(BAKERY, "002", 3000); Product product3 = createProduct(HANDMADE, "003", 5000); productRepository.s..

Test Doubles ์ •๋ฆฌ

Test Double ์ด๋ž€?ํ…Œ์ŠคํŠธ ๋”๋ธ”์ด๋ž€ ์‹ค์ œ ๊ฐ์ฒด๋ฅผ ๋Œ€์‹ ํ•ด์„œ ํ…Œ์ŠคํŒ…์—์„œ ์‚ฌ์šฉํ•˜๋Š” ๋ชจ๋“  ๋ฐฉ๋ฒ•์„ ์ผ์ปฌ์–ด ํ˜ธ์นญํ•˜๋Š” ๊ฒƒ์ด๋‹ค. Test DoubleDummy: ์•„๋ฌด๊ฒƒ๋„ ํ•˜์ง€ ์•Š๋Š” ๊นกํ†ต ๊ฐ์ฒดFake: ๋‹จ์ˆœํ•œ ํ˜•ํƒœ๋กœ ๋™์ผํ•œ ๊ธฐ๋Šฅ์€ ์ˆ˜ํ–‰ํ•˜๋‚˜, ํ”„๋กœ๋•์…˜์—์„œ ์“ฐ๊ธฐ์—๋Š” ๋ถ€์กฑํ•œ ๊ฐ์ฒด (ex. FakeRepository)Stub: ํ…Œ์ŠคํŠธ์—์„œ ์š”์ฒญํ•œ ๊ฒƒ์— ๋Œ€ํ•ด ๋ฏธ๋ฆฌ ์ค€๋น„ํ•œ ๊ฒฐ๊ณผ๋ฅผ ์ œ๊ณตํ•˜๋Š” ๊ฐ์ฒด. ๊ทธ ์™ธ์—๋Š” ์‘๋‹ตํ•˜์ง€ ์•Š๋Š”๋‹ค.Spy: Stub์ด๋ฉด์„œ ํ˜ธ์ถœ๋œ ๋‚ด์šฉ์„ ๊ธฐ๋กํ•˜์—ฌ ๋ณด์—ฌ์ค„ ์ˆ˜ ์žˆ๋Š” ๊ฐ์ฒด. ์ผ๋ถ€๋Š” ์‹ค์ œ ๊ฐ์ฒด์ฒ˜๋Ÿผ ๋™์ž‘์‹œํ‚ค๊ณ  ์ผ๋ถ€๋งŒ Stubbing ํ•  ์ˆ˜ ์žˆ๋‹ค.Mock: ํ–‰์œ„์— ๋Œ€ํ•œ ๊ธฐ๋Œ€๋ฅผ ๋ช…์„ธํ•˜๊ณ , ๊ทธ์— ๋”ฐ๋ผ ๋„์ž‘ํ•˜๋„๋ก ๋งŒ๋“ค์–ด์ง„ ๊ฐ์ฒด Mocks Aren't StubsMock๊ณผ Stub์€ ๋‹ค๋ฅด๋‹ค. Stub - ์ƒํƒœ ๊ฒ€์ฆ(Stat..

Presentation Layer ํ…Œ์ŠคํŠธ

์šฉ์–ด ์ •๋ฆฌ- `MockMvc`: ์‹ค์ œ ์„œ๋ธ”๋ฆฟ ์ปจํ…Œ์ด๋„ˆ ์—†์ด๋„ MVC ๋™์ž‘์„ ๋ชจ์˜(mock)ํ•˜์—ฌ ํ…Œ์ŠคํŠธํ•  ์ˆ˜ ์žˆ๋„๋ก Spring์—์„œ ์ œ๊ณตํ•˜๋Š” ํ…Œ์ŠคํŠธ ํ”„๋ ˆ์ž„์›Œํฌ- `@WebMvcTest`: @SpringBootTest๊ฐ€ ์ „์ฒด ๋นˆ์„ ๋ชจ๋‘ ๋„์šฐ๋Š” ํ…Œ์ŠคํŠธ ์–ด๋…ธํ…Œ์ด์…˜์ด์—ˆ๋‹ค๋ฉด, @WebMvcTest๋Š” ์ปจํŠธ๋กค๋Ÿฌ ๊ด€๋ จ ๋นˆ๋“ค๋งŒ ๋„์šฐ๋Š” ๊ฐ€๋ฒผ์šด ํ…Œ์ŠคํŠธ ์–ด๋…ธํ…Œ์ด์…˜- `@MockBean`: Spring ์ปจํ…์ŠคํŠธ์—์„œ ๋นˆ์„ ๋ชจ์˜(mock) ๊ฐ์ฒด๋กœ ๊ต์ฒดํ•  ๋•Œ ์‚ฌ์šฉํ•˜๋Š” ์–ด๋…ธํ…Œ์ด์…˜ @Mock vs @MockBean@Mock: ์Šคํ”„๋ง ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์ปจํ…์ŠคํŠธ๋ฅผ ๋กœ๋”ฉํ•˜์ง€ ์•Š๊ณ ๋„ ์‚ฌ์šฉ ํ•  ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์—, ์Šคํ”„๋ง ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์ปจํ…์ŠคํŠธ๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š” ์ˆœ์ˆ˜ ๋‹จ์œ„ ํ…Œ์ŠคํŠธ์—์„œ ๋ชจ์˜ ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•˜๋Š” ๋ฐ ์ ํ•ฉ (์„œ๋น„์Šค ํ…Œ์ŠคํŠธ)@MockBean: ์Šคํ”„๋ง ์• ..

@SpringBootTest vs @DataJpaTest

@SpringBootTestํŠน์ง•โœ… ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ์ „์ฒด ์ปจํ…์ŠคํŠธ๋ฅผ ๋กœ๋“œํ•˜์—ฌ ํ†ตํ•ฉ ํ…Œ์ŠคํŠธ๋ฅผ ์ˆ˜ํ–‰ํ•œ๋‹ค.โœ… ๋ชจ๋“  ๋นˆ(Bean)์„ ์ดˆ๊ธฐํ™”ํ•˜๋ฏ€๋กœ JPA๋ฟ๋งŒ ์•„๋‹ˆ๋ผ ์„œ๋น„์Šค, ์ปจํŠธ๋กค๋Ÿฌ, ๊ธฐํƒ€ ์˜์กด์„ฑ๊นŒ์ง€ ํฌํ•จ๋œ๋‹ค.โœ… ๋‚ด๋ถ€์ ์œผ๋กœ @Transactional ์–ด๋…ธํ…Œ์ด์…˜์ด ์—†์–ด, ํ…Œ์ŠคํŠธ ํ›„ ๋ฐ์ดํ„ฐ๋ฅผ ์ •๋ฆฌํ•˜๋ ค๋ฉด tearDown() ๋ฉ”์„œ๋“œ๋ฅผ ์ง์ ‘ ์ •์˜ํ•ด์•ผ ํ•œ๋‹ค.์žฅ๋‹จ์ โœ… ์žฅ์ : ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์ „์ฒด๋ฅผ ํ…Œ์ŠคํŠธํ•  ์ˆ˜ ์žˆ์–ด ํ†ตํ•ฉ ํ…Œ์ŠคํŠธ์— ์ ํ•ฉํ•˜๋‹ค.โœ… ๋‹จ์ : ํ…Œ์ŠคํŠธ๊ฐ€ ๋ฌด๊ฒ๊ณ , ์‹คํ–‰ ์‹œ๊ฐ„์ด ์ƒ๋Œ€์ ์œผ๋กœ ์˜ค๋ž˜ ๊ฑธ๋ฆด ์ˆ˜ ์žˆ๋‹ค. @DataJpaTestํŠน์ง•โœ… JPA ๊ด€๋ จ ์ปดํฌ๋„ŒํŠธ(Repository, EntityManager ๋“ฑ)๋งŒ ์ดˆ๊ธฐํ™”ํ•˜์—ฌ ํ…Œ์ŠคํŠธํ•œ๋‹ค.โœ… @SpringBootTest๋ณด๋‹ค ๊ฐ€๋ณ๊ณ  ๋น ๋ฅด๊ฒŒ ์‹คํ–‰๋œ๋‹ค.โœ… ๋‚ด์žฅ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค(H2 ๋“ฑ)๋ฅผ ํ™œ์šฉํ•ด ..

Persistence Layer ํ…Œ์ŠคํŠธ

Repository ํ…Œ์ŠคํŠธ๋ฅผ ์™œ ํ•ด์•ผํ• ๊นŒ?1. JPA ๋ฉ”์„œ๋“œ๊ฐ€ ์ž‘์„ฑ์ž์˜ ์˜๋„๋Œ€๋กœ ์ฟผ๋ฆฌ๋ฅผ ์ƒ์„ฑํ•˜๊ณ  ์‹คํ–‰ํ•˜๋Š”์ง€ ๊ฒ€์ฆํ•˜๊ธฐ ์œ„ํ•ด๊ฐœ๋ฐœ์ž๋Š” ์ฝ”๋“œ์— ๊ธฐ๋ฐ˜ํ•œ ๋กœ์ง์ด ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ์ž‘๋™ํ•œ๋‹ค๊ณ  ๋ฏฟ์„ ์ˆ˜ ์žˆ์ง€๋งŒ, ์‹ค์ œ๋กœ ์ƒ์„ฑ๋œ ์ฟผ๋ฆฌ๊ฐ€ ๊ธฐ๋Œ€์™€ ๋‹ค๋ฅผ ์ˆ˜ ์žˆ๋‹ค! 2. ๋ฏธ๋ž˜์˜ ๋ณ€๊ฒฝ ์‚ฌํ•ญ์— ๋Œ€๋น„ํ•˜๊ธฐ ์œ„ํ•ดํ˜„์žฌ JPA๋ฅผ ์‚ฌ์šฉํ•˜๋”๋ผ๋„ ํ–ฅํ›„ QueryDSL, MyBatis์™€ ๊ฐ™์€ ๋‹ค๋ฅธ ๊ธฐ์ˆ ๋กœ ๋ณ€๊ฒฝ๋  ๊ฐ€๋Šฅ์„ฑ์ด ์žˆ๋‹ค. Repository ํ…Œ์ŠคํŠธ๋ฅผ ์ž˜ ๊ตฌ์„ฑํ•ด ๋‘๋ฉด, ์ด๋Ÿฌํ•œ ๋ณ€๊ฒฝ์—๋„ ์•ˆ์ •์ ์œผ๋กœ ๋™์ž‘์„ ๊ฒ€์ฆํ•  ์ˆ˜ ์žˆ๋‹ค. Repository ์ฝ”๋“œ@Repositorypublic interface ProductRepository extends JpaRepository { /** * select * * from product * wh..

๋ ˆ์ด์–ด๋“œ ์•„ํ‚คํ…์ฒ˜(Layered Architecture)์™€ ํ…Œ์ŠคํŠธ

๋ ˆ์ด์–ด๋“œ ์•„ํ‚คํ…์ฒ˜์‚ฌ์šฉ์ž ์š”์ฒญ์ด ์™”์„ ๋•Œ ๋ ˆ์ด์–ด๋ณ„๋กœ ์š”์ฒญ์„ ์ฒ˜๋ฆฌํ•˜์ž! -> ๊ด€์‹ฌ์‚ฌ์˜ ๋ถ„๋ฆฌ๊ด€์‹ฌ์‚ฌ๋ฅผ ๋ถ„๋ฆฌํ•จ์œผ๋กœ์จ ์ฑ…์ž„์„ ๋‚˜๋ˆ„๊ณ  ์œ ์ง€๋ณด์ˆ˜ํ•˜๊ธฐ ์šฉ์ดํ•˜๊ฒŒ ๋งŒ๋“ค ์ˆ˜ ์žˆ๋‹ค. Presentation Layer, Business Layer, Persistence Layer ๋กœ ๋‚˜๋ˆ„๊ณ , ์ด๋ฅผ 3-Tier๋ผ๊ณ  ๋ถ€๋ฅด๊ธฐ๋„ ํ•œ๋‹ค.์กฐ๊ธˆ ๋” ์ž์„ธํžˆ ๋‚˜๋ˆ„๊ณ  ์‹ถ๋‹ค๋ฉด Persistence Layer ํ•˜์œ„์— Infrastructure Layer๋ฅผ ๋‘๊ณ  4-Tier๋กœ ๋‚˜๋ˆ„๊ธฐ๋„ ํ•œ๋‹ค. Presentation Layerโœ… ์™ธ๋ถ€ ์„ธ๊ณ„์˜ ์š”์ฒญ์„ ๊ฐ€์žฅ ๋จผ์ € ๋ฐ›๋Š” ๊ณ„์ธตโœ… ํŒŒ๋ผ๋ฏธํ„ฐ์— ๋Œ€ํ•œ ์ตœ์†Œํ•œ์˜ ๊ฒ€์ฆ์„ ์ˆ˜ํ–‰ํ•œ๋‹ค. Business Layerโœ… ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง์„ ๊ตฌํ˜„ํ•˜๋Š” ์—ญํ• โœ… Persistence Layer์™€์˜ ์ƒํ˜ธ์ž‘์šฉ(Data๋ฅผ ์ฝ๊ณ  ์“ฐ๋Š” ํ–‰์œ„)๋ฅผ ํ†ตํ•ด ..