TestCode์ ๋ฐ์ดํฐ๋ฒ ์ด์ค ์๋ฒ ์ฐ๋
by rlaehddnd0422์ ํ๋ฆฌ์ผ์ด์ ์๋ฒ์์ ์ฌ์ฉํ๋ ๋ฐ์ดํฐ๋ฒ ์ด์ค ์๋ฒ์ ํ ์คํธ์์ ์ฌ์ฉํ๋ ๋ฐ์ดํฐ๋ฒ ์ด์ค ์๋ฒ๊ฐ ๋์ผํ๋ฉด ํ ์คํธ์ ์ํฅ์ ๋ผ์น ์ ์์ต๋๋ค.
์๋ฅผ๋ค๋ฉด ์ ํ๋ฆฌ์ผ์ด์ ์๋ฒ์์ ์ฌ์ฉํ๋ ๋ฐ์ดํฐ๋ฒ ์ด์ค ์๋ฒ์ Item ํ ์ด๋ธ์ ๋ช ๊ฐ์ ๋ฐ์ดํฐ๊ฐ ์กด์ฌํ๋ค๊ณ ํ ๋,
ํ ์คํธ์์ ์ด ๋ฐ์ดํฐ๋ฒ ์ด์ค๋ฅผ ๊ฐ์ง๊ณ ๊ฒ์ ๋ฉ์๋ findItems()๋ฅผ ์คํํ์ ๋, ๊ธฐ์กด์ ๋ฐ์ดํฐ๋ค๋ก ์ธํด ํ ์คํธ์ ์คํจํ๊ฒ ๋ฉ๋๋ค.
@Test
void findItems() {
//given
Item item1 = new Item("itemA-1", 10000, 10);
Item item2 = new Item("itemA-2", 20000, 20);
Item item3 = new Item("itemB-1", 30000, 30);
log.info("repository={}", itemRepository.getClass());
itemRepository.save(item1);
itemRepository.save(item2);
itemRepository.save(item3);
//๋ ๋ค ์์ ๊ฒ์ฆ
test(null, null, item1, item2, item3);
test("", null, item1, item2, item3);
//itemName ๊ฒ์ฆ
test("itemA", null, item1, item2);
test("temA", null, item1, item2);
test("itemB", null, item3);
//maxPrice ๊ฒ์ฆ
test(null, 10000, item1);
//๋ ๋ค ์์ ๊ฒ์ฆ
test("itemA", 10000, item1);
}
void test(String itemName, Integer maxPrice, Item... items) {
List<Item> result = itemRepository.findAll(new ItemSearchCond(itemName, maxPrice));
assertThat(result).containsExactly(items);
}
๋ฐ๋ผ์ ์ด๋ฐ ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๊ธฐ ์ํด์๋ ํ ์คํธ๋ฅผ ๋ค๋ฅธ ํ๊ฒฝ๊ณผ ์ฒ ์ ํ๊ฒ ๋ถ๋ฆฌํด์ผ ํฉ๋๋ค.
๊ฐ์ฅ ๊ฐ๋จํ๊ฒ๋ ํ ์คํธ ์ ์ฉ ๋ฐ์ดํฐ๋ฒ ์ด์ค๋ฅผ ๋ณ๋๋ก ์ด์ํ๋ ๋ฐฉ๋ฒ์ด ์์ต๋๋ค.
- jdbc:h2:tcp://localhost/~/test : ์ ํ๋ฆฌ์ผ์ด์ ์๋ฒ์์ ์ฌ์ฉํ๋ ๋ฐ์ดํฐ๋ฒ ์ด์ค ์๋ฒ (local)
- jdbc:h2:tcp://localhost/~/testcase : ํ ์คํธ์์ ์ฌ์ฉํ๋ ์ ์ฉ ๋ฐ์ดํฐ๋ฒ ์ด์ค ์๋ฒ (test)
src/main/resources/application.properties
spring.profiles.active=local
spring.datasource.url=jdbc:h2:tcp://localhost/~/test
spring.datasource.username=sa
src/test/resources/application.properties
spring.profiles.active=test
spring.datasource.url=jdbc:h2:tcp://localhost/~/testcase
spring.datasource.username=sa
ํ ์คํธ์ ์ ํ๋ฆฌ์ผ์ด์ ์์ ์ฌ์ฉํ๋ ๋ฐ์ดํฐ๋ฒ ์ด์ค๋ฅด ๋ถ๋ฆฌํด๋ณด์์ต๋๋ค. ํ์ง๋ง ๋์ด ์๋๋๋ค.
ํ ์คํธ๊ฐ ๋๋๋ฉด ํ ์คํธ์์ ์์ฑํ ๋ฐ์ดํฐ๋ค์ ์ญ์ ํด์ฃผ์ด์ผ ๋ค์ ํ ์คํธ์ ์ํฅ์ ๋ผ์น์ง ์์ต๋๋ค.
์ด๋ป๊ฒ ํด์ผ ํ ๊น์?
Solution1. ํธ๋์ญ์ ๊ณผ ๋กค๋ฐฑ ์ ๋ต
์ด ๋ ๋์์ด ๋๋ ๊ฒ์ด ๋ฐ๋ก ํธ๋์ญ์ ์ ๋๋ค.
ํ ์คํธ๊ฐ ๋๋๊ณ ๋ ํ ํธ๋์ญ์ ์ ๊ฐ์ ๋ก ๋กค๋ฐฑํด๋ฒ๋ฆฌ๋ฉด ๋ฐ์ดํฐ๊ฐ ๊น๋ํ๊ฒ ์ง์์ง๋๋ค.
๋ง์ฝ ํ ์คํธ ์คํ๋์ค ์ค๊ฐ์ ํ ์คํธ๊ฐ ์คํจํด์ ๋กค๋ฐฑ์ ํธ์ถํ์ง ๋ชปํด๋ ํธ๋์ญ์ ๋ชจ๋๋ก ์ ํํ๊ธฐ ๋๋ฌธ์ ์ปค๋ฐํ์ง ์์ ์ด์ ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ๋ฐ์๋์ง ์์ต๋๋ค.
ํ ์คํธ๊ฐ ์คํํ๊ธฐ ์ ์ด๋ ๊ฒ @BeforeEach๋ก ํธ๋์ญ์ ์ ์์ํด์ฃผ๊ณ ,
@Slf4j
@SpringBootTest
class ItemRepositoryTest {
@Autowired
ItemRepository itemRepository;
@Autowired
PlatformTransactionManager transactionManager;
TransactionStatus status;
@BeforeEach
void init()
{
status = transactionManager.getTransaction(new DefaultTransactionDefinition());
}
ํ ์คํธ๊ฐ ๋๋๋ฉด ์ด๋ ๊ฒ @AfterEach๋ก ๋กค๋ฐฑํด์ฃผ๋ฉด ๋ฉ๋๋ค.
@AfterEach
void afterEach() {
//MemoryItemRepository ์ ๊ฒฝ์ฐ ์ ํ์ ์ผ๋ก ์ฌ์ฉ
if (itemRepository instanceof MemoryItemRepository) {
((MemoryItemRepository) itemRepository).clearStore();
}
transactionManager.rollback(status);
}
์ฐธ๊ณ ๋ก ํธ๋์ญ์ ๋งค๋์ ๋ ์คํ๋ง ๋ถํธ๊ฐ application.properties์ ๋ฑ๋ก๋ ์ ๋ณด๋ฅผ ํตํด DataSource์ ๋๋ถ์ด ์๋์ผ๋ก ์์ฑ๋๊ธฐ ๋๋ฌธ์ ๋ณ๋๋ก ๋ฑ๋กํ์ง ์์๋ ์๋ํฉ๋๋ค.
Solution2. @Transactional
ํธ๋์ญ์ ๋งค๋์ ๋ฅผ ์ฌ์ฉํ์ง ์์ผ๋ฉด์, ํธ๋์ญ์ ์ ์ ์ฉํ๋ ๋ฐฉ๋ฒ์ด ์์์ต๋๋ค. ๋ฐ๋ก AOP @Transactional ๋ฐฉ์์ด์ฃ .
ํ ์คํธ ์ฝ๋์๋ ๋ง์ฐฌ๊ฐ์ง๋ก @Transactional์ ์ ์ฉํ ์ ์์ต๋๋ค.
@Transactional
@Slf4j
@SpringBootTest
class ItemRepositoryTest {
@Autowired
ItemRepository itemRepository;
// @Autowired
// PlatformTransactionManager transactionManager;
//
// TransactionStatus status;
//
// @BeforeEach
// void init()
// {
// status = transactionManager.getTransaction(new DefaultTransactionDefinition());
// }
@AfterEach
void afterEach() {
//MemoryItemRepository ์ ๊ฒฝ์ฐ ์ ํ์ ์ผ๋ก ์ฌ์ฉ
if (itemRepository instanceof MemoryItemRepository) {
((MemoryItemRepository) itemRepository).clearStore();
}
// transactionManager.rollback(status);
}
@Transactional์ ํ ์คํธ์์ ์ฌ์ฉํ๋ฉด ์กฐ๊ธ ํน๋ณํ๊ฒ ๋์ํฉ๋๋ค.
@Transactional์ด ์ ์ฉ๋ ํ ์คํธ ๋์ ๋ฐฉ์
@Transactional์ด ํ ์คํธ์ ์์ผ๋ฉด ์คํ๋ง์ ํ ์คํธ๋ฅผ ํธ๋์ญ์ ์์์ ์คํํ๊ณ , ํ ์คํธ๊ฐ ๋๋๋ฉด ์๋์ผ๋ก ๋กค๋ฐฑ์ ์์ผ๋ฒ๋ฆฝ๋๋ค!
๋ฐ๋ผ์ ํ ์คํธ๊ฐ ๋๋ ํ ๊ฐ๋ฐ์๋ ๋ฐ๋ก ์ง์ ๋ฐ์ดํฐ๋ฅผ ์ญ์ ํ์ง ์์๋ ๋ฉ๋๋ค.
Q. ๋ง์ฝ ํ ์คํธ ์ฝ๋์ ํ ์คํธ ์คํ ๋จ๊ณ์์ ์๋น์ค๋ ๋ฆฌํฌ์งํ ๋ฆฌ๋ฅผ ํธ์ถํด์ ์ฌ์ฉํ๋๋ฐ ์๋น์ค๋ ๋ฆฌํฌ์งํ ๋ฆฌ ๊ณ์ธต์ @Transactional์ด ๋ถ์ด์์ผ๋ฉด ์ด๋ป๊ฒ ์ฒ๋ฆฌ๋๋๊ฐ?
A. ์๋น์ค๋ ๋ฆฌํฌ์งํ ๋ฆฌ ๊ณ์ธต์ ํธ๋์ญ์ ๋ ํ ์คํธ์์ ์์ํ ํธ๋์ญ์ ์ ์ฐธ์ฌํ๊ฒ ๋์ด, ํ ์คํธ์ ์คํ๋ถํฐ ๋๊น์ง ๋ด๋ถ ์ฝ๋๊ฐ ๊ฐ์ ํธ๋์ญ์ ์ ์ฌ์ฉํฉ๋๋ค.
Q. ํ ์คํธ๊ฐ ์ ์๋ํ๋์ง ๋ฐ์ดํฐ๋ฒ ์ด์ค์์ ํ์ธํ๊ณ ์ถ์ด ์ปค๋ฐํ๊ณ ์ถ์ ๊ฒฝ์ฐ์๋ ์ด๋ป๊ฒ ํ๋ฉด ๋๋๊ฐ?
A. ํ ์คํธ ๋ฉ์๋์์ @Commit์ด๋ , @Rollback(false)๋ก ์ด๋ ธํ ์ด์ ์ ๋ถํ์ฃผ๋ฉด ๋กค๋ฐฑํ์ง ์๊ณ ํธ๋์ญ์ ์ด ์ปค๋ฐ๋ฉ๋๋ค.
Solution3. ์๋ฒ ๋๋ ๋ชจ๋ DB
ํ ์คํธ ์ผ์ด์ค๋ฅผ ์คํํ๊ธฐ ์ํด์ ๋ณ๋์ ๋ฐ์ดํฐ๋ฒ ์ด์ค๋ฅผ ์ค์นํ๊ณ , ์ด์ํ๋ ๊ฒ์ ์๋นํ ๋ฒ์กํ ์์ ์ ๋๋ค.
๋จ์ํ ํ ์คํธ๋ฅผ ๊ฒ์ฆํ ์ฉ๋๋ก๋ง ์ฌ์ฉํ๊ธฐ ๋๋ฌธ์ ํ ์คํธ๊ฐ ๋๋๋ฉด ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ๋ฐ์ดํฐ๋ฅผ ๋ชจ๋ ์ญ์ ํด๋ ๋๋ค. ๋ ๋์๊ฐ์ ํ ์คํธ๊ฐ ๋๋๋ฉด ๋ฐ์ดํฐ๋ฒ ์ด์ค ์์ฒด๋ฅผ ์ ๊ฑฐํด๋ ๋ฉ๋๋ค. ์ด๋ด ๋ ์๋ฒ ๋๋ ๋ชจ๋๋ฅผ ์ฌ์ฉํ ์ ์์ต๋๋ค.
์๋ฒ ๋๋ ๋ชจ๋๋ ๋ณ๋์ ๋ฐ์ดํฐ๋ฒ ์ด์ค๋ฅผ ์ค์นํ์ง ์๊ณ , ์ฌ์ฉํ๊ณ ์ถ์ ๋ฐ์ดํฐ๋ฒ ์ด์ค ์๋ฒ๋ฅผ JVM ์์์ ๋ฉ๋ชจ๋ฆฌ ๋ชจ๋๋ก ๋์ํ๊ฒ ํ๋ ๋ฐฉ์์ ๋๋ค. ์ฐ๋ฆฌ๊ฐ ์ง๊ธ๊น์ง ์ฌ์ฉํ H2 DB๋ ์๋ฐ๋ก ๊ฐ๋ฐ๋์ด ์๊ณ , JVM ์์์ ๋ฉ๋ชจ๋ฆฌ ๋ชจ๋๋ก ๋์ํ ์ ์๋๋ก ์ง์ํฉ๋๋ค.
DB๋ฅผ ์ ํ๋ฆฌ์ผ์ด์ ์ ๋ด์ฅํด์ ํจ๊ป ์คํํ๋ค๊ณ ํด์ ์๋ฒ ๋๋ ๋ชจ๋๋ผ๊ณ ํฉ๋๋ค.
์๋ฒ ๋๋ ๋ชจ๋ ์ง์ ์ฌ์ฉํ๊ธฐ
์ ํ๋ฆฌ์ผ์ด์ ์คํ ์ฝ๋์ DataSource๋ฅผ ์๋์ผ๋ก ๋ฉ๋ชจ๋ฆฌ๋ชจ๋๋ก ๋น ๋ฑ๋ก
@Bean
@Profile("test")
public DataSource dataSource()
{
log.info("๋ฉ๋ชจ๋ฆฌ ๋ฐ์ดํฐ๋ฒ ์ด์ค ์ด๊ธฐํ");
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName("org.h2.Driver");
dataSource.setUrl("jdbc:h2:mem:db;DB_CLOSE_DELAY=-1");
dataSource.setUsername("sa");
dataSource.setPassword("");
return dataSource;
}
- @Profile("test") : ํ๋กํ์ด test์ธ ๊ฒฝ์ฐ์๋ง ์ ์ฉ. ์ฆ ํ ์คํธ ์ฝ๋์๋ง ์ ์ฉํ๊ฒ ๋ค๋ ์๋ฏธ
- DataSource ๋ฑ๋กํ ๋ jdbc:h2:mem:db ๋ก ์์ฑํ๋ฉด ์๋ฒ ๋๋ ๋ชจ๋(๋ฉ๋ชจ๋ฆฌ ๋ชจ๋)๋ก ๋์ํ๋ H2 ๋ฐ์ดํฐ๋ฒ ์ด์ค๋ฅผ ์ฌ์ฉํ ์ ์์ต๋๋ค.
- DB_CLOSE_DELAY=-1 : ์๋ฒ ๋๋ ๋ชจ๋์์๋ ๋ฐ์ดํฐ๋ฒ ์ด์ค ์ปค๋ฅ์ ์ด ์ฐ๊ฒฐ์ด ๋ชจ๋ ๋์ด์ง๋ฉด ๋ฐ์ดํฐ๋ฒ ์ด์ค๋ ์ข ๋ฃ๋๋ ๋ฐ -1๋ก ์ค์ ํ๋ฉด ์ด๊ฒ์ ๋ฐฉ์งํ ์ ์์ต๋๋ค.
์ฌ์ค ์คํ๋ง๋ถํธ๋ ์๋ฒ ๋๋ ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ๋ํ ์ค์ ๋ ๊ธฐ๋ณธ์ผ๋ก ์ ๊ณตํ๋ ๋๋ถ์
// @Bean
// @Profile("test")
// public DataSource dataSource()
// {
// log.info("๋ฉ๋ชจ๋ฆฌ ๋ฐ์ดํฐ๋ฒ ์ด์ค ์ด๊ธฐํ");
// DriverManagerDataSource dataSource = new DriverManagerDataSource();
// dataSource.setDriverClassName("org.h2.Driver");
// dataSource.setUrl("jdbc:h2:mem:db;DB_CLOSE_DELAY=-1");
// dataSource.setUsername("sa");
// dataSource.setPassword("");
// return dataSource;
// }
spring.profiles.active=test
#spring.datasource.url=jdbc:h2:tcp://localhost/~/testcase
#spring.datasource.username=sa
์ด๋ ๊ฒ ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ์ ๊ทผํ๋ ๋ชจ๋ ์ค์ ์ ๋ณด๋ฅผ ์ง์ฐ๊ฒ ๋๋ฉด ์คํ๋ง ๋ถํธ๋ ์๋์ผ๋ก ์๋ฒ ๋๋ ๋ชจ๋๋ก ์ ๊ทผํ๋ ๋ฐ์ดํฐ์์ค๋ฅผ ๋ง๋ค์ด์ ์ ๊ณตํฉ๋๋ค.
<์ ๋ฆฌ>
์ด๋ ๊ฒ ํ ์คํธ์ฝ๋์์ ๋ฐ์ดํฐ๋ฒ ์ด์ค ์๋ฒ์ ์ ๊ทผํ ๋ ์๊ธธ ์ ์๋ ๋ฌธ์ ( ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ๋ฐ์ดํฐ๊ฐ ์ ์ง๋์ด ํ ์คํธ์ ์ํฅ์ ๋ผ์น๋ ๋ฌธ์ )๋ฅผ ํตํด ํด๊ฒฐํด๋ณด์์ต๋๋ค.
- ์ฒซ ๋ฒ์งธ, ์ ํ๋ฆฌ์ผ์ด์ ์๋ฒ์ ํ ์คํธ ์๋ฒ์ ๋ฐ์ดํฐ๋ฒ ์ด์ค ๋ถ๋ฆฌ.
- ๋ ๋ฒ์งธ, ํธ๋์ญ์ ์ ์ด์ฉํด ํ ์คํธ๊ฐ ๋๋๋ฉด ํ ์คํธ ์๋ฒ์ ๋ฐ์ดํฐ๋ฒ ์ด์ค ๋กค๋ฐฑ
- ์ธ ๋ฒ์งธ, TestCode์์ ํน๋ณํ๊ฒ ๋์ํ๋ @Transactional์ ์ด์ฉํ ํ ์คํธ ํ ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ๋ฐ์ดํฐ ๋กค๋ฐฑ
- ๋ค ๋ฒ์งธ, ์๋ฒ ๋๋ ๋ชจ๋๋ฅผ ํตํด ํ ์คํธ ํ ๋ฐ์ดํฐ๋ฒ ์ด์ค ์ ๊ฑฐ.
<์ฐธ๊ณ ์๋ฃ>
'๐ Backend > DB Access' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
[Spring Data JPA] ์คํ๋ง ๋ฐ์ดํฐ JPA (0) | 2023.04.17 |
---|---|
[JPA] JPA(Java Persistent API) (0) | 2023.04.17 |
[JdbcTemplate] JdbcTemplate ์ ์ฉ (0) | 2023.04.12 |
[JdbcTemplate] RowMapper์ ๋ํด (0) | 2023.04.12 |
[JdbcTemplate] JDBC Template ์ด๋? (0) | 2023.04.07 |
๋ธ๋ก๊ทธ์ ์ ๋ณด
Study Repository
rlaehddnd0422