[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 ๋ฑ ๊ธฐ๋ณธ์ ์ธ ๊ฒ๋ง ์ดํด๋ดค์ต๋๋ค.
'Programming > Spring' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
[Spring boot] MVC ํจํด์ ์ด์ฉํ REST API ๊ฐ๋ฐ (3) | 2020.05.19 |
---|---|
[Spring boot] REST API์ ๊ธฐ์ด์ ์ค๊ณ (0) | 2020.05.19 |
[Spring boot] ๋๋ง์ ํ๊ฒฝ ์ค์ ๋ง๋ค๊ธฐ (0) | 2020.04.22 |
[Spring boot] ํ๊ฒฝ ์ค์ ์ ๋์ ์๋ฆฌ์ ์ ํ๋ฆฌ์ผ์ด์ ํ๊ฒฝ ๋๋๊ธฐ (0) | 2020.04.21 |
[Spring boot] ๋ค์ํ ์ด๋ ธํ ์ด์ ์ ํ์ฉํ HTTP API ๊ตฌํ (0) | 2020.04.21 |