TestCodeμ λ°μ΄ν°λ² μ΄μ€ μλ² μ°λ
μ ν리μΌμ΄μ μλ²μμ μ¬μ©νλ λ°μ΄ν°λ² μ΄μ€ μλ²μ ν μ€νΈμμ μ¬μ©νλ λ°μ΄ν°λ² μ΄μ€ μλ²κ° λμΌνλ©΄ ν μ€νΈμ μν₯μ λΌμΉ μ μμ΅λλ€.
μλ₯Όλ€λ©΄ μ ν리μΌμ΄μ μλ²μμ μ¬μ©νλ λ°μ΄ν°λ² μ΄μ€ μλ²μ 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μ μ΄μ©ν ν μ€νΈ ν λ°μ΄ν°λ² μ΄μ€μ λ°μ΄ν° λ‘€λ°±
- λ€ λ²μ§Έ, μλ² λλ λͺ¨λλ₯Ό ν΅ν΄ ν μ€νΈ ν λ°μ΄ν°λ² μ΄μ€ μ κ±°.
<μ°Έκ³ μλ£>
μ€νλ§ DB 2νΈ - λ°μ΄ν° μ κ·Ό νμ© κΈ°μ - μΈνλ° | κ°μ
λ°±μλ κ°λ°μ νμν DB λ°μ΄ν° μ κ·Ό κΈ°μ μ νμ©νκ³ , μμ±ν μ μμ΅λλ€. μ€νλ§ DB μ κ·Ό κΈ°μ μ μ리μ ꡬ쑰λ₯Ό μ΄ν΄νκ³ , λ κΉμ΄μλ λ°±μλ κ°λ°μλ‘ μ±μ₯ν μ μμ΅λλ€., - κ°μ μκ° | μΈ
www.inflearn.com