๐ ์คํ๋ง ๋ถํธ ํ ์คํธ: @SpringBootTest ํ์ฉํ๊ธฐ ๐งช

์๋ , ์น๊ตฌ๋ค! ์ค๋์ ์ ๋ง ํฅ๋ฏธ์ง์งํ ์ฃผ์ ๋ก ์ฐพ์์์ด. ๋ฐ๋ก ์คํ๋ง ๋ถํธ ํ ์คํธ์ @SpringBootTest ์ด๋ ธํ ์ด์ ์ ๋ํด ๊น์ด ํํค์ณ๋ณผ ๊ฑฐ์ผ. ๐ ์ด ๊ธ์ ์ฝ๊ณ ๋๋ฉด ๋ํฌ๋ ํ ์คํธ ๋ง์คํฐ๊ฐ ๋ ์ ์์ ๊ฑฐ์ผ! ์, ์ค๋น๋๋? ๊ทธ๋ผ ์์ํด๋ณด์๊ณ !
์ ๊น! ํน์ ๋ํฌ ์ค์ ์ฌ๋ฅ๋ท(https://www.jaenung.net)์ด๋ผ๋ ์ฌ์ดํธ ๋ค์ด๋ดค์ด? ์ฌ๊ธฐ์ ํ๋ก๊ทธ๋๋ฐ ์ค๋ ฅ์ ๊ณต์ ํ๊ณ ๋ฐฐ์ธ ์ ์๋. ๋์ค์ ์ฐ๋ฆฌ๊ฐ ๋ฐฐ์ด ์คํ๋ง ๋ถํธ ํ ์คํธ ๊ธฐ์ ๋ก ๋ฉ์ง ํ๋ก์ ํธ๋ฅผ ๋ง๋ค์ด์ ๊ณต์ ํด๋ณด๋ ๊ฑด ์ด๋? ๐ค
1. ์คํ๋ง ๋ถํธ ํ ์คํธ๋ ๋ญ์ผ? ๐คทโโ๏ธ
์, ๋จผ์ ์คํ๋ง ๋ถํธ ํ ์คํธ๊ฐ ๋ญ์ง๋ถํฐ ์์๋ณด์. ๊ฐ๋จํ ๋งํด์, ์คํ๋ง ๋ถํธ ํ ์คํธ๋ ์ฐ๋ฆฌ๊ฐ ๋ง๋ ์ ํ๋ฆฌ์ผ์ด์ ์ด ์ ๋๋ก ๋์ํ๋์ง ํ์ธํ๋ ๋ฐฉ๋ฒ์ด์ผ. ๋ง์น ์๋ฆฌ์ฌ๊ฐ ์์ ๋ง์ ๋ณด๋ ๊ฒ์ฒ๋ผ, ์ฐ๋ฆฌ๋ ์ฝ๋์ '๋ง'์ ๋ณด๋ ๊ฑฐ์ง! ๐
์คํ๋ง ๋ถํธ ํ ์คํธ๋ ์ฐ๋ฆฌ ์ ํ๋ฆฌ์ผ์ด์ ์ ํ์ง์ ๋ณด์ฅํ๊ณ , ๋ฒ๊ทธ๋ฅผ ๋ฏธ๋ฆฌ ์ก์๋ด๋ ๋ฐ ํฐ ๋์์ ์ค.
์ด๊ฒ ์ ์ค์ํ๋๊ณ ? ์์ํด๋ด. ๋ค๊ฐ ๋ง๋ ์ฑ์ด ์๋ง์ ์ฌ์ฉ์๋ค์๊ฒ ๋ฐฐํฌ๋๋๋ฐ, ๊ฐ์๊ธฐ ํฐ ์ค๋ฅ๊ฐ ๋ฐ์ํ๋ค๋ฉด? ๐ฑ ์์ฐํ์ง ์์? ๊ทธ๋์ ์ฐ๋ฆฌ๋ ํ ์คํธ๋ฅผ ํตํด ์ด๋ฐ ์ผ์ด ์ผ์ด๋์ง ์๋๋ก ๋ฏธ๋ฆฌ๋ฏธ๋ฆฌ ์ค๋นํ๋ ๊ฑฐ์ผ.์ ๊ทธ๋ฆผ์ ๋ณด๋ฉด ์คํ๋ง ๋ถํธ ํ ์คํธ์ ๊ธฐ๋ณธ ํ๋ฆ์ ์ดํดํ ์ ์์ด. ์ฝ๋๋ฅผ ์์ฑํ๊ณ , ํ ์คํธ๋ฅผ ์คํํ ๋ค์, ๊ทธ ๊ฒฐ๊ณผ๋ฅผ ํ์ธํ๋ ๊ณผ์ ์ด์ง. ์ด ๊ณผ์ ์ ๋ฐ๋ณตํ๋ฉด์ ์ฐ๋ฆฌ๋ ์ ์ ๋ ์์ ์ ์ด๊ณ ๋ฏฟ์ ์ ์๋ ์ ํ๋ฆฌ์ผ์ด์ ์ ๋ง๋ค์ด๊ฐ ์ ์์ด.
2. @SpringBootTest ์ด๋ ธํ ์ด์ ์ ๋น๋ฐ ๐ต๏ธโโ๏ธ
์, ์ด์ ์ฐ๋ฆฌ์ ์ฃผ์ธ๊ณต @SpringBootTest ์ด๋ ธํ ์ด์ ์ ๋ํด ์์๋ณผ ์ฐจ๋ก์ผ. ์ด ๋ ์, ๊ฒ๋ณด๊ธฐ์ ๋ณ ๊ฑฐ ์๋ ๊ฒ ๊ฐ์ง๋ง, ์ค์ ์์ฒญ๋ ํ์ ๊ฐ์ง๊ณ ์์ด!
@SpringBootTest๋ ์คํ๋ง ๋ถํธ ์ ํ๋ฆฌ์ผ์ด์ ์ ์ํ ํ ์คํธ ํ๊ฒฝ์ ์์ฝ๊ฒ ๊ตฌ์ฑํด์ฃผ๋ ๋ง๋ฒ ๊ฐ์ ์ด๋ ธํ ์ด์ ์ด์ผ.
์ด ์ด๋ ธํ ์ด์ ์ ์ฌ์ฉํ๋ฉด, ์ค์ ์ ํ๋ฆฌ์ผ์ด์ ๊ณผ ๊ฑฐ์ ๋์ผํ ํ๊ฒฝ์์ ํ ์คํธ๋ฅผ ์คํํ ์ ์์ง. coolํ์ง ์์? ๐๐จ ์ฃผ์! @SpringBootTest๋ ๊ฐ๋ ฅํ์ง๋ง, ๊ทธ๋งํผ ๋ฆฌ์์ค๋ฅผ ๋ง์ด ์ฌ์ฉํด. ๋ชจ๋ ํ ์คํธ์ ๋ฌด์์ ์ฌ์ฉํ๋ฉด ํ ์คํธ ์คํ ์๊ฐ์ด ๊ธธ์ด์ง ์ ์์ผ๋ ๊ผญ ํ์ํ ๊ฒฝ์ฐ์๋ง ์ฌ์ฉํ์!
์, ์ด์ @SpringBootTest๋ฅผ ์ด๋ป๊ฒ ์ฌ์ฉํ๋์ง ๊ฐ๋จํ ์์ ๋ฅผ ํตํด ์ดํด๋ณด์.
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
public class MyAwesomeTest {
@Test
void contextLoads() {
// ์ฌ๊ธฐ์ ํ
์คํธ ๋ก์ง์ ์์ฑํด
}
}
์ ์ฝ๋๋ฅผ ๋ณด๋ฉด, ํด๋์ค ์์ @SpringBootTest ์ด๋ ธํ ์ด์ ์ ๋ถ์์ด. ์ด๋ ๊ฒ ํ๋ฉด ์คํ๋ง ๋ถํธ๊ฐ ํ ์คํธ๋ฅผ ์ํ ์ ํ๋ฆฌ์ผ์ด์ ์ปจํ ์คํธ๋ฅผ ์์ฑํด์ค. ๊ทธ๋ฆฌ๊ณ @Test ์ด๋ ธํ ์ด์ ์ด ๋ถ์ ๋ฉ์๋๊ฐ ์ค์ ํ ์คํธ ์ผ์ด์ค๊ฐ ๋๋ ๊ฑฐ์ง.
ํ์ง๋ง ์ด๊ฒ ๋ค๊ฐ ์๋์ผ! @SpringBootTest๋ ์ฌ๋ฌ ๊ฐ์ง ์ต์ ์ ์ ๊ณตํด์ ํ ์คํธ ํ๊ฒฝ์ ๋ ์ธ๋ฐํ๊ฒ ์ ์ดํ ์ ์์ด. ์๋ฅผ ๋ค์ด:
- webEnvironment: ์น ํ๊ฒฝ ์ค์
- properties: ํ ์คํธ์ฉ ํ๋กํผํฐ ์ค์
- classes: ํน์ ์ค์ ํด๋์ค๋ง ๋ก๋
์ด๋ฐ ์ต์ ๋ค์ ํ์ฉํ๋ฉด ์ ๋ง ๋ค์ํ ์ํฉ์ ๋ง๋ ํ ์คํธ๋ฅผ ์์ฑํ ์ ์์ด. ์๋ฅผ ๋ค์ด, ์น ์๋ฒ๋ฅผ ์ค์ ๋ก ๋์ฐ๊ณ ์ถ๋ค๋ฉด ์ด๋ ๊ฒ ํ ์ ์์ง:
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class MyWebTest {
// ํ
์คํธ ์ฝ๋
}
์ด๋ ๊ฒ ํ๋ฉด ์ค์ ์น ์๋ฒ๊ฐ ๋๋ค ํฌํธ๋ก ์์๋๊ณ , ๊ทธ ์ํ์์ ํ ์คํธ๊ฐ ์คํ๋ผ. ๋ง์น ์ค์ ์ด์ ํ๊ฒฝ๊ณผ ๋น์ทํ ์ํฉ์์ ํ ์คํธํ ์ ์๋ ๊ฑฐ์ง!
3. @SpringBootTest์ ๋ด๋ถ ๋์ ์๋ฆฌ ๐
์, ์ด์ @SpringBootTest๊ฐ ์ด๋ป๊ฒ ๋์ํ๋์ง ๋ ์์ธํ ๋ค์ฌ๋ค๋ณผ ์๊ฐ์ด์ผ. ์ด ๋ ์์ด ์ด๋ป๊ฒ ๊ทธ๋ ๊ฒ ๊ฐ๋ ฅํ ํ ์คํธ ํ๊ฒฝ์ ๋ง๋ค์ด๋ด๋ ๊ฑธ๊น? ๐ค
@SpringBootTest๋ ์คํ๋ง ๋ถํธ์ ์๋ ๊ตฌ์ฑ(Auto-configuration) ๊ธฐ๋ฅ์ ์ต๋ํ ํ์ฉํด.
์ด๊ฒ ๋ฌด์จ ๋ง์ด๋๋ฉด, ์ค์ ์ ํ๋ฆฌ์ผ์ด์ ์ ์์ํ ๋์ฒ๋ผ ํ์ํ ๋ชจ๋ ๋น(Bean)๋ค์ ์๋์ผ๋ก ๋ฑ๋กํ๊ณ ๊ตฌ์ฑํ๋ค๋ ๊ฑฐ์ผ. ์ ๋ง ๋๋ํ์ง?@SpringBootTest์ ๋์ ๊ณผ์ ์ ๊ฐ๋จํ ์ ๋ฆฌํ๋ฉด ์ด๋ ๊ฒ ๋ผ:
- ํ ์คํธ ํด๋์ค๋ฅผ ์ค์บํ๊ณ @SpringBootTest ์ด๋ ธํ ์ด์ ์ ๋ฐ๊ฒฌํด.
- ์คํ๋ง ๋ถํธ ์ ํ๋ฆฌ์ผ์ด์ ์ปจํ ์คํธ๋ฅผ ์์ฑํด.
- @SpringBootApplication์ด ๋ถ์ ๋ฉ์ธ ํด๋์ค๋ฅผ ์ฐพ์ ๊ตฌ์ฑ ์ ๋ณด๋ก ์ฌ์ฉํด.
- application.properties (๋๋ application.yml) ํ์ผ์ ์ค์ ์ ๋ก๋ํด.
- ์๋ ๊ตฌ์ฑ์ ํตํด ํ์ํ ๋น๋ค์ ๋ฑ๋กํ๊ณ ์ด๊ธฐํํด.
- ํ ์คํธ์ ํ์ํ ์ถ๊ฐ์ ์ธ ๊ตฌ์ฑ์ ์ ์ฉํด (์: ์น ํ๊ฒฝ ์ค์ ).
- ๋ชจ๋ ์ค๋น๊ฐ ๋๋๋ฉด ํ ์คํธ ๋ฉ์๋๋ฅผ ์คํํด.
์ด ๊ณผ์ ์ ๊ฑฐ์น๋ฉด์ @SpringBootTest๋ ์ฐ๋ฆฌ๊ฐ ์ค์ ์ ํ๋ฆฌ์ผ์ด์ ์ ์คํํ์ ๋์ ๊ฑฐ์ ๋์ผํ ํ๊ฒฝ์ ๋ง๋ค์ด๋ด๋ ๊ฑฐ์ผ. ๊ทธ๋์ ํตํฉ ํ ์คํธ๋ฅผ ์ํํ๊ธฐ์ ์๋ฒฝํ ์กฐ๊ฑด์ด ๋๋ ๊ฑฐ์ง!
ํ์ง๋ง ์ด๋ฐ ๊ฐ๋ ฅํ ๊ธฐ๋ฅ์๋ ๋น์ฐํ ๋๊ฐ๊ฐ ๋ฐ๋ฅด์ง. ๋ฐ๋ก ํ ์คํธ ์คํ ์๊ฐ์ด ๊ธธ์ด์ง ์ ์๋ค๋ ๊ฑฐ์ผ. ์ ์ฒด ์ ํ๋ฆฌ์ผ์ด์ ์ปจํ ์คํธ๋ฅผ ๋ก๋ํ๋ ๊ฒ ๊ฝค ๋ฌด๊ฑฐ์ด ์์ ์ด๊ฑฐ๋ . ๊ทธ๋์ ๋จ์ ํ ์คํธ์ฒ๋ผ ๊ฐ๋ฒผ์ด ํ ์คํธ์๋ @SpringBootTest ๋์ ๋ค๋ฅธ ๊ฐ๋ฒผ์ด ํ ์คํธ ์ด๋ ธํ ์ด์ ์ ์ฌ์ฉํ๋ ๊ฒ ์ข์.
๐ก ๊ฟํ: ํ ์คํธ ์คํ ์๊ฐ์ ์ค์ด๊ณ ์ถ๋ค๋ฉด, ํ ์คํธ ํด๋์ค๋ค ์ฌ์ด์ @DirtiesContext ์ด๋ ธํ ์ด์ ์ ์ ์ ํ ์ฌ์ฉํด๋ด. ์ด ์ด๋ ธํ ์ด์ ์ ์คํ๋ง์๊ฒ "์ด ํ ์คํธ๊ฐ ๋๋๋ฉด ์ปจํ ์คํธ๋ฅผ ์๋ก ๋ง๋ค์ด์ผ ํด"๋ผ๊ณ ์๋ ค์ฃผ๋ ์ญํ ์ ํด. ์ปจํ ์คํธ๋ฅผ ์ฌ์ฌ์ฉํ ์ ์๋ ์ํฉ์์๋ ํ ์คํธ ์คํ ์๋๋ฅผ ํฌ๊ฒ ๋์ผ ์ ์์ง!
4. @SpringBootTest ์ค์ ํ์ฉ ์์ ๐ช
์, ์ด์ @SpringBootTest๋ฅผ ์ค์ ๋ก ์ด๋ป๊ฒ ํ์ฉํ๋์ง ๋ช ๊ฐ์ง ์์ ๋ฅผ ํตํด ์ดํด๋ณด์. ์ด๋ก ๋ง ์๋ฉด ๋ญํด, ์ค์ ์์ ์จ๋จน์ ์ค ์์์ผ์ง! ๐
4.1 ๊ธฐ๋ณธ์ ์ธ ํตํฉ ํ ์คํธ
๋จผ์ ๊ฐ์ฅ ๊ธฐ๋ณธ์ ์ธ ํํ์ ํตํฉ ํ ์คํธ๋ถํฐ ์์ํด๋ณผ๊น?
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
public class UserServiceIntegrationTest {
@Autowired
private UserService userService;
@Test
void testCreateUser() {
User user = new User("testuser", "test@example.com");
User createdUser = userService.createUser(user);
assertNotNull(createdUser.getId());
assertEquals("testuser", createdUser.getUsername());
assertEquals("test@example.com", createdUser.getEmail());
}
}
์ด ํ ์คํธ์์๋ UserService๋ฅผ ์ฃผ์ ๋ฐ์ ์ค์ ๋ก ์ฌ์ฉ์๋ฅผ ์์ฑํ๋ ๊ธฐ๋ฅ์ ํ ์คํธํ๊ณ ์์ด. @SpringBootTest ๋๋ถ์ ์ค์ ์ ํ๋ฆฌ์ผ์ด์ ๊ณผ ๋์ผํ ํ๊ฒฝ์์ UserService๊ฐ ์ ๋๋ก ๋์ํ๋์ง ํ์ธํ ์ ์์ง.
4.2 ์น ์ ํ๋ฆฌ์ผ์ด์ ํ ์คํธ
์น ์ ํ๋ฆฌ์ผ์ด์ ์ ํ ์คํธํ ๋๋ ์ค์ HTTP ์์ฒญ์ ๋ณด๋ด๊ณ ์๋ต์ ํ์ธํด์ผ ํ ๋๊ฐ ์์ด. ์ด๋ด ๋ @SpringBootTest์ TestRestTemplate์ ํจ๊ป ์ฌ์ฉํ๋ฉด ์์ฃผ ํธ๋ฆฌํด!
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.web.client.TestRestTemplate;
import org.springframework.boot.web.server.LocalServerPort;
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class UserControllerIntegrationTest {
@LocalServerPort
private int port;
@Autowired
private TestRestTemplate restTemplate;
@Test
void testGetUser() {
String url = "http://localhost:" + port + "/api/users/1";
ResponseEntity<user> response = restTemplate.getForEntity(url, User.class);
assertEquals(HttpStatus.OK, response.getStatusCode());
assertNotNull(response.getBody());
assertEquals("testuser", response.getBody().getUsername());
}
}
</user>
์ฌ๊ธฐ์๋ @SpringBootTest์ webEnvironment ์ต์ ์ RANDOM_PORT๋ก ์ค์ ํด์ ์ค์ ์น ์๋ฒ๋ฅผ ๋๋ค ํฌํธ๋ก ์์ํ์ด. ๊ทธ๋ฆฌ๊ณ TestRestTemplate์ ์ฌ์ฉํด HTTP GET ์์ฒญ์ ๋ณด๋ด๊ณ ์๋ต์ ํ์ธํ๊ณ ์์ง. ์ด๋ ๊ฒ ํ๋ฉด ์ปจํธ๋กค๋ฌ๋ถํฐ ์๋น์ค, ๋ฆฌํฌ์งํ ๋ฆฌ๊น์ง ์ ์ฒด ํ๋ก์ฐ๋ฅผ ํ ๋ฒ์ ํ ์คํธํ ์ ์์ด!
4.3 ๋ฐ์ดํฐ๋ฒ ์ด์ค ์ฐ๋ ํ ์คํธ
๋ฐ์ดํฐ๋ฒ ์ด์ค์ ์ฐ๋๋ ๊ธฐ๋ฅ์ ํ ์คํธํ ๋๋ @SpringBootTest๊ฐ ํฐ ๋์์ด ๋ผ. ์๋ฅผ ๋ค์ด, JPA๋ฅผ ์ฌ์ฉํ๋ ๋ฆฌํฌ์งํ ๋ฆฌ๋ฅผ ํ ์คํธํ๋ค๊ณ ํด๋ณด์.
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.transaction.annotation.Transactional;
@SpringBootTest
@Transactional
public class UserRepositoryIntegrationTest {
@Autowired
private UserRepository userRepository;
@Test
void testSaveAndFindUser() {
User user = new User("testuser", "test@example.com");
userRepository.save(user);
User foundUser = userRepository.findByUsername("testuser");
assertNotNull(foundUser);
assertEquals("test@example.com", foundUser.getEmail());
}
}
์ด ํ ์คํธ์์๋ @Transactional ์ด๋ ธํ ์ด์ ์ ์ถ๊ฐ๋ก ์ฌ์ฉํ์ด. ์ด๋ ๊ฒ ํ๋ฉด ๊ฐ ํ ์คํธ ๋ฉ์๋๊ฐ ํธ๋์ญ์ ๋ด์์ ์คํ๋๊ณ , ํ ์คํธ๊ฐ ๋๋๋ฉด ์๋์ผ๋ก ๋กค๋ฐฑ๋ผ. ๋๋ถ์ ํ ์คํธ ๋ฐ์ดํฐ๊ฐ ์ค์ DB์ ๋จ์ง ์์์ ํ ์คํธ ๊ฒฉ๋ฆฌ์ฑ์ ์ ์งํ ์ ์์ง.
4.4 ์ธ๋ถ ์๋น์ค ๋ชจํน ํ ์คํธ
๋๋ก๋ ์ธ๋ถ ์๋น์ค์ ์์กดํ๋ ๊ธฐ๋ฅ์ ํ ์คํธํด์ผ ํ ๋๊ฐ ์์ด. ์ด๋ด ๋๋ @MockBean์ ์ฌ์ฉํด์ ์ธ๋ถ ์๋น์ค๋ฅผ ๋ชจํนํ ์ ์์ด.
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.mock.mockito.MockBean;
@SpringBootTest
public class WeatherServiceIntegrationTest {
@Autowired
private WeatherService weatherService;
@MockBean
private ExternalWeatherApi externalWeatherApi;
@Test
void testGetWeatherForecast() {
when(externalWeatherApi.getForecast("Seoul"))
.thenReturn(new Forecast("Sunny", 25));
Weather weather = weatherService.getWeatherForecast("Seoul");
assertEquals("Sunny", weather.getCondition());
assertEquals(25, weather.getTemperature());
}
}
์ฌ๊ธฐ์๋ ExternalWeatherApi๋ฅผ @MockBean์ผ๋ก ์ ์ธํด์ ์ค์ ์ธ๋ถ API๋ฅผ ํธ์ถํ์ง ์๊ณ ๋ WeatherService๋ฅผ ํ ์คํธํ ์ ์๊ฒ ํ์ด. ์ด๋ ๊ฒ ํ๋ฉด ๋คํธ์ํฌ ๋ฌธ์ ๋ ์ธ๋ถ ์๋น์ค์ ๋ถ์์ ์ฑ์ ์ํฅ๋ฐ์ง ์๊ณ ์์ ์ ์ผ๋ก ํ ์คํธ๋ฅผ ์ํํ ์ ์์ง.
๐จ ์ฃผ์! @MockBean์ ์ฌ์ฉํ ๋๋ ์ฃผ์๊ฐ ํ์ํด. ์ด ์ด๋ ธํ ์ด์ ์ ์คํ๋ง ์ปจํ ์คํธ๋ฅผ ์์ ํ๊ธฐ ๋๋ฌธ์, ๊ณผ๋ํ๊ฒ ์ฌ์ฉํ๋ฉด ํ ์คํธ ์คํ ์๊ฐ์ด ๊ธธ์ด์ง ์ ์์ด. ๊ผญ ํ์ํ ๊ฒฝ์ฐ์๋ง ์ฌ์ฉํ๋ ๊ฒ ์ข์!
5. @SpringBootTest์ ๊ณ ๊ธ ๊ธฐ๋ฅ ๐
์, ์ด์ @SpringBootTest์ ๋ ๊ณ ๊ธ์ค๋ฌ์ด ๊ธฐ๋ฅ๋ค์ ์ดํด๋ณผ ์ฐจ๋ก์ผ. ์ด ๋ ์์ ์ ๋ง ๋ค์ฌ๋ค๋ฅํด์, ์ฐ๋ฆฌ๊ฐ ์์ํ๋ ๊ฑฐ์ ๋ชจ๋ ํ ์คํธ ์๋๋ฆฌ์ค๋ฅผ ์ปค๋ฒํ ์ ์์ด!
5.1 ํ ์คํธ์ฉ ์ค์ ์ค๋ฒ๋ผ์ด๋ฉ
๋๋ก๋ ํ ์คํธ ํ๊ฒฝ์์๋ง ํน๋ณํ ์ค์ ์ ์ ์ฉํ๊ณ ์ถ์ ๋๊ฐ ์์ง? ์ด๋ด ๋ @SpringBootTest์ properties ์์ฑ์ ์ฌ์ฉํ๋ฉด ๋ผ.
@SpringBootTest(properties = {
"spring.datasource.url=jdbc:h2:mem:testdb",
"spring.jpa.hibernate.ddl-auto=create-drop"
})
public class CustomConfigTest {
// ํ
์คํธ ์ฝ๋
}
์ด๋ ๊ฒ ํ๋ฉด ํ ์คํธ ์คํ ์ ์ง์ ํ ํ๋กํผํฐ๋ค์ด ๊ธฐ์กด ์ค์ ์ ์ค๋ฒ๋ผ์ด๋ํด. ์๋ฅผ ๋ค์ด, ์ ์ฝ๋์์๋ ํ ์คํธ์ฉ ์ธ๋ฉ๋ชจ๋ฆฌ H2 ๋ฐ์ดํฐ๋ฒ ์ด์ค๋ฅผ ์ฌ์ฉํ๋๋ก ์ค์ ํ์ด. ์ค์ ์ด์ DB๋ฅผ ๊ฑด๋๋ฆฌ์ง ์๊ณ ํ ์คํธํ ์ ์๊ฒ ๋๋ ๊ฑฐ์ง!
5.2 ํ ์คํธ ํ๋กํ์ผ ํ์ฑํ
์คํ๋ง์ ํ๋กํ์ผ ๊ธฐ๋ฅ์ ์ด์ฉํด ํ ์คํธ์ฉ ์ค์ ์ ๋ฐ๋ก ๊ด๋ฆฌํ๊ณ ์ถ๋ค๋ฉด @ActiveProfiles ์ด๋ ธํ ์ด์ ์ ์ฌ์ฉํ ์ ์์ด.
@SpringBootTest
@ActiveProfiles("test")
public class TestProfileActivationTest {
// ํ
์คํธ ์ฝ๋
}
์ด๋ ๊ฒ ํ๋ฉด application-test.properties (๋๋ application-test.yml) ํ์ผ์ ์ค์ ์ด ์ ์ฉ๋ผ. ํ ์คํธ ํ๊ฒฝ์ ํนํ๋ ์ค์ ์ ๋ณ๋๋ก ๊ด๋ฆฌํ ์ ์์ด ์์ฃผ ํธ๋ฆฌํ์ง!
5.3 ํ ์คํธ์ฉ ์ ํ๋ฆฌ์ผ์ด์ ์ค์ ํด๋์ค ์ฌ์ฉ
๋๋ก๋ ํ ์คํธ์์๋ง ์ฌ์ฉํ ํน๋ณํ ๋น์ด๋ ์ค์ ์ด ํ์ํ ์ ์์ด. ์ด๋ด ๋๋ @TestConfiguration์ ์ฌ์ฉํด ํ ์คํธ์ฉ ์ค์ ํด๋์ค๋ฅผ ๋ง๋ค ์ ์์ด.
@SpringBootTest
public class CustomTestConfigurationTest {
@TestConfiguration
static class TestConfig {
@Bean
public DataSource dataSource() {
return new EmbeddedDatabaseBuilder()
.setType(EmbeddedDatabaseType.H2)
.build();
}
}
@Autowired
private DataSource dataSource;
@Test
void testCustomDataSource() {
assertNotNull(dataSource);
assertTrue(dataSource instanceof EmbeddedDatabase);
}
}
์ด ์์ ์์๋ ํ ์คํธ์์๋ง ์ฌ์ฉํ ์๋ฒ ๋๋ ๋ฐ์ดํฐ๋ฒ ์ด์ค๋ฅผ ์ค์ ํ๊ณ ์์ด. @TestConfiguration ๋๋ถ์ ์ด ์ค์ ์ ํ ์คํธ ์คํ ์์๋ง ์ ์ฉ๋๊ณ , ์ค์ ์ ํ๋ฆฌ์ผ์ด์ ์คํ์๋ ์ํฅ์ ์ฃผ์ง ์์.
5.4 ์ฌ๋ผ์ด์ค ํ ์คํธ์์ ์กฐํฉ
@SpringBootTest๋ ์ ์ฒด ์ ํ๋ฆฌ์ผ์ด์ ์ปจํ ์คํธ๋ฅผ ๋ก๋ํ์ง๋ง, ๋๋ก๋ ํน์ ๋ ์ด์ด๋ง ํ ์คํธํ๊ณ ์ถ์ ๋๊ฐ ์์ด. ์ด๋ด ๋ ์ฌ๋ผ์ด์ค ํ ์คํธ ์ด๋ ธํ ์ด์ ๊ณผ ์กฐํฉํด์ ์ฌ์ฉํ ์ ์์ด.
@SpringBootTest
@AutoConfigureMockMvc
public class ControllerSliceTest {
@Autowired
private MockMvc mockMvc;
@Test
void testGetUser() throws Exception {
mockMvc.perform(get("/api/users/1"))
.andExpect(status().isOk())
.andExpect(jsonPath("$.username").value("testuser"));
}
}
์ด ์์ ์์๋ @SpringBootTest์ @AutoConfigureMockMvc๋ฅผ ํจ๊ป ์ฌ์ฉํด ์ปจํธ๋กค๋ฌ ๋ ์ด์ด๋ฅผ ํ ์คํธํ๊ณ ์์ด. MockMvc๋ฅผ ์ด์ฉํด HTTP ์์ฒญ์ ์๋ฎฌ๋ ์ด์ ํ๊ณ , ์๋ต์ ๊ฒ์ฆํ ์ ์์ง.
5.5 ๋น๋๊ธฐ ํ ์คํธ
๋ง์ฝ ๋น๋๊ธฐ ์์ ์ ํ ์คํธํด์ผ ํ๋ค๋ฉด, @SpringBootTest์ ํจ๊ป @Async ์ด๋ ธํ ์ด์ ์ ์ฌ์ฉํ ์ ์์ด.
@SpringBootTest
public class AsyncServiceTest {
@Autowired
private AsyncService asyncService;
@Test
void testAsyncMethod() throws Exception {
CompletableFuture<string> future = asyncService.asyncMethod();
String result = future.get(5, TimeUnit.SECONDS);
assertEquals("Async result", result);
}
}
</string>
์ด ํ ์คํธ์์๋ ๋น๋๊ธฐ ๋ฉ์๋์ ๊ฒฐ๊ณผ๋ฅผ ๊ธฐ๋ค๋ฆฌ๊ณ ์์ด. CompletableFuture๋ฅผ ์ฌ์ฉํด ์ต๋ 5์ด ๋์ ๊ฒฐ๊ณผ๋ฅผ ๊ธฐ๋ค๋ฆฌ๋๋ก ์ค์ ํ์ง. ์ด๋ ๊ฒ ํ๋ฉด ๋น๋๊ธฐ ์์ ๋ ์์ ํ๊ฒ ํ ์คํธํ ์ ์์ด!
๐ก ๊ฟํ: ๋น๋๊ธฐ ํ ์คํธ๋ฅผ ํ ๋๋ ํ์์์ ์ค์ ์ ์ฃผ์ํด์ผ ํด. ๋๋ฌด ์งง๊ฒ ์ค์ ํ๋ฉด ํ ์คํธ๊ฐ ๋ถ์์ ํด์ง ์ ์๊ณ , ๋๋ฌด ๊ธธ๊ฒ ์ค์ ํ๋ฉด ํ ์คํธ ์คํ ์๊ฐ์ด ๋ถํ์ํ๊ฒ ๊ธธ์ด์ง ์ ์์ด. ์ ์ ํ ํ์์์ ๊ฐ์ ์ฐพ๋ ๊ฒ ์ค์ํด!
6. @SpringBootTest ์ฌ์ฉ ์ ์ฃผ์์ฌํญ โ ๏ธ
@SpringBootTest๋ ์ ๋ง ๊ฐ๋ ฅํ ๋๊ตฌ์ง๋ง, ๊ทธ๋งํผ ์ฃผ์ํด์ ์ฌ์ฉํด์ผ ํด. ์ฌ๊ธฐ ๋ช ๊ฐ์ง ์ฃผ์์ฌํญ์ ์ ๋ฆฌํด๋ดค์ด.
6.1 ํ ์คํธ ์คํ ์๊ฐ
@SpringBootTest๋ ์ ์ฒด ์ ํ๋ฆฌ์ผ์ด์ ์ปจํ ์คํธ๋ฅผ ๋ก๋ํ๊ธฐ ๋๋ฌธ์, ํ ์คํธ ์คํ ์๊ฐ์ด ๊ธธ์ด์ง ์ ์์ด. ํนํ ํ ์คํธ ์ผ์ด์ค๊ฐ ๋ง์์ง์๋ก ์ด ๋ฌธ์ ๋ ๋ ์ฌ๊ฐํด์ง ์ ์์ง.
ํด๊ฒฐ์ฑ : ๊ฐ๋ฅํ ํ ์ฌ๋ผ์ด์ค ํ ์คํธ(@WebMvcTest, @DataJpaTest ๋ฑ)๋ฅผ ํ์ฉํ๊ณ , ๊ผญ ํ์ํ ๊ฒฝ์ฐ์๋ง @SpringBootTest๋ฅผ ์ฌ์ฉํด. ๋ํ, ํ ์คํธ ํด๋์ค ๊ฐ์ ์ ํ๋ฆฌ์ผ์ด์ ์ปจํ ์คํธ๋ฅผ ๊ณต์ ํ ์ ์๋๋ก ์ค๊ณํ๋ ๊ฒ๋ ์ข์.
6.2 ํ ์คํธ ๊ฒฉ๋ฆฌ
- ์ง์์ธ์ ์ฒ - ์ง์ ์ฌ์ฐ๊ถ ๋ณดํธ ๊ณ ์ง
์ง์ ์ฌ์ฐ๊ถ ๋ณดํธ ๊ณ ์ง
- ์ ์๊ถ ๋ฐ ์์ ๊ถ: ๋ณธ ์ปจํ ์ธ ๋ ์ฌ๋ฅ๋ท์ ๋ ์ AI ๊ธฐ์ ๋ก ์์ฑ๋์์ผ๋ฉฐ, ๋ํ๋ฏผ๊ตญ ์ ์๊ถ๋ฒ ๋ฐ ๊ตญ์ ์ ์๊ถ ํ์ฝ์ ์ํด ๋ณดํธ๋ฉ๋๋ค.
- AI ์์ฑ ์ปจํ ์ธ ์ ๋ฒ์ ์ง์: ๋ณธ AI ์์ฑ ์ปจํ ์ธ ๋ ์ฌ๋ฅ๋ท์ ์ง์ ์ฐฝ์๋ฌผ๋ก ์ธ์ ๋๋ฉฐ, ๊ด๋ จ ๋ฒ๊ท์ ๋ฐ๋ผ ์ ์๊ถ ๋ณดํธ๋ฅผ ๋ฐ์ต๋๋ค.
- ์ฌ์ฉ ์ ํ: ์ฌ๋ฅ๋ท์ ๋ช ์์ ์๋ฉด ๋์ ์์ด ๋ณธ ์ปจํ ์ธ ๋ฅผ ๋ณต์ , ์์ , ๋ฐฐํฌ, ๋๋ ์์ ์ ์ผ๋ก ํ์ฉํ๋ ํ์๋ ์๊ฒฉํ ๊ธ์ง๋ฉ๋๋ค.
- ๋ฐ์ดํฐ ์์ง ๊ธ์ง: ๋ณธ ์ปจํ ์ธ ์ ๋ํ ๋ฌด๋จ ์คํฌ๋ํ, ํฌ๋กค๋ง, ๋ฐ ์๋ํ๋ ๋ฐ์ดํฐ ์์ง์ ๋ฒ์ ์ ์ฌ์ ๋์์ด ๋ฉ๋๋ค.
- AI ํ์ต ์ ํ: ์ฌ๋ฅ๋ท์ AI ์์ฑ ์ปจํ ์ธ ๋ฅผ ํ AI ๋ชจ๋ธ ํ์ต์ ๋ฌด๋จ ์ฌ์ฉํ๋ ํ์๋ ๊ธ์ง๋๋ฉฐ, ์ด๋ ์ง์ ์ฌ์ฐ๊ถ ์นจํด๋ก ๊ฐ์ฃผ๋ฉ๋๋ค.
์ฌ๋ฅ๋ท์ ์ต์ AI ๊ธฐ์ ๊ณผ ๋ฒ๋ฅ ์ ๊ธฐ๋ฐํ์ฌ ์์ฌ์ ์ง์ ์ฌ์ฐ๊ถ์ ์ ๊ทน์ ์ผ๋ก ๋ณดํธํ๋ฉฐ,
๋ฌด๋จ ์ฌ์ฉ ๋ฐ ์นจํด ํ์์ ๋ํด ๋ฒ์ ๋์์ ํ ๊ถ๋ฆฌ๋ฅผ ๋ณด์ ํฉ๋๋ค.
ยฉ 2025 ์ฌ๋ฅ๋ท | All rights reserved.
๋๊ธ 0๊ฐ