https://velog.io/@mooh2jj/Todolist-TestCode-만들기
이 블로그에서 JUnit5를 이용한 단위테스트를 살펴보았습니다.
이번에는 실제 상용할 DB에 연결
해서 Test 작업을 하는 것은 통합 테스트
을 똑같이 Todolist 작업을 예시로 살펴보겠습니다.
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@AutoConfigureMockMvc
@SpringBootTest
: 관련된 지식은 이 블로그를 참조해주실 바랍니다.@AutoConfigureMockMvc
: @SpringBootTest`이 설정한 모킹한 객체를 의존성주입하기 위한 설정, 테스트대상이 되는 Controller뿐만 아니라 @Service, @Repository가 붙은 객체들도 모두 메모리에 올립니다.기존에 단위테스츠 Controller testCode에서 given() 절들을 Repository 메서드로 체인지
해주면 됩니다.
통합테스트에서는 Service 인터페이스를 사용하지 않았습니다.
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@AutoConfigureMockMvc
public class TodoControllerIntegrationTest {
@Autowired
private MockMvc mvc;
@Autowired
private TodoRepository todoRepository;
@Autowired
private ObjectMapper mapper;
@BeforeEach
void setup() {
todoRepository.deleteAll();
}
@Test
void create() throws Exception {
TodoEntity todoEntity = TodoEntity.builder()
.title("dsgIT")
.order(1L)
.completed(false)
.build();
TodoRequest todoRequest = TodoRequest.builder()
.title(todoEntity.getTitle())
.order(todoEntity.getOrder())
.completed(todoEntity.getCompleted())
.build();
mvc.perform(post("/todo")
.contentType(MediaType.APPLICATION_JSON)
.content(mapper.writeValueAsString(todoRequest)))
.andExpect(status().isCreated())
.andExpect(jsonPath("$.title").value(todoEntity.getTitle()))
.andExpect(jsonPath("$.order").value(todoEntity.getOrder()))
.andExpect(jsonPath("$.completed").value(todoEntity.getCompleted()))
.andDo(print());
}
@Test
void readOne() throws Exception {
TodoEntity todoEntity = TodoEntity.builder()
.title("dsgIT")
.order(1L)
.completed(false)
.build();
todoRepository.save(todoEntity);
mvc.perform(get("/todo/{id}", todoEntity.getId()))
.andExpect(status().isOk())
.andExpect(content().contentType(MediaType.APPLICATION_JSON))
.andExpect(jsonPath("$.id").value(todoEntity.getId()))
.andExpect(jsonPath("$.title").value(todoEntity.getTitle()))
.andExpect(jsonPath("$.order").value(todoEntity.getOrder()))
.andExpect(jsonPath("$.completed").value(todoEntity.getCompleted()));
}
@Test
void readOneException() throws Exception {
Long todoId = 100L;
TodoEntity todoEntity = TodoEntity.builder()
.title("dsgIT")
.order(1L)
.completed(false)
.build();
todoRepository.save(todoEntity);
mvc.perform(get("/todo/{id}", todoId))
.andExpect(status().isNotFound());
}
@Test
void readAll() throws Exception {
int expectedLength = 10;
IntStream.rangeClosed(1,expectedLength).forEach(i -> {
TodoEntity todoEntity = TodoEntity.builder()
.title("todo_dsg"+"_"+i)
.order((long) i)
.completed(true)
.build();
todoRepository.save(todoEntity);
});
mvc.perform(get("/todo"))
.andExpect(status().isOk())
.andExpect(jsonPath("$.size()").value(expectedLength));
}
@Test
public void updateById() throws Exception {
TodoEntity todoEntity = TodoEntity.builder()
.title("dsgIT")
.order(1L)
.completed(false)
.build();
TodoEntity savedTodo = todoRepository.save(todoEntity);
mvc.perform(put("/todo/{id}", savedTodo.getId())
.contentType(MediaType.APPLICATION_JSON))
.andDo(print())
.andExpect(status().isOk())
.andExpect(jsonPath("$.title", CoreMatchers.is(savedTodo.getTitle())))
.andExpect(jsonPath("$.order", CoreMatchers.is(1))) // 1L이라 오류날수 있어 value 1 넣음
.andExpect(jsonPath("$.completed", CoreMatchers.is(true)));
}
@Test
public void deleteById() throws Exception {
TodoEntity todoEntity = TodoEntity.builder()
.title("dsgIT")
.order(1L)
.completed(false)
.build();
TodoEntity savedTodo = todoRepository.save(todoEntity);
mvc.perform(delete("/todo/{id}", savedTodo.getId()))
.andDo(print())
.andExpect(status().isOk());
}
@Test
void deleteAll() throws Exception {
int expectedLength = 10;
List<TodoEntity> todos = new ArrayList<>();
IntStream.rangeClosed(1,expectedLength).forEach(i -> {
TodoEntity todoEntity = TodoEntity.builder()
.title("todo_dsg"+"_"+i)
.order((long) i)
.completed(true)
.build();
todos.add(todoEntity);
});
List<TodoEntity> savedTodos = todoRepository.saveAll(todos);
todoRepository.deleteAll(savedTodos);
mvc.perform(delete("/todo"))
.andExpect(status().isOk());
}
}
기존에 @DataJpaTest
와 함께 @AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)
만 추가해주면 됩니다.
@DataJpaTest
@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)
// 내장형 DB는 사용하지 않는다는 설정
실제예제
@Import(JpaAuditConfig.class)
@DataJpaTest
@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)
@Rollback(value = false)
class ItemTest {
@Autowired
private ItemRepository itemRepository;
@Test
public void saveTest() {
LongStream.rangeClosed(1, 10).forEach(i -> {
Item item = Item.builder()
.id(i)
.name("test 상품_" + i)
.price(10000 + (int)i)
.description("test_상품_상세_설명" + i)
.status(ItemSellStatus.SELL)
.stock(100)
.build();
itemRepository.save(item);
});
}
}
charset utf-8 변경
ALTER TABLE shop.items convert to charset UTF8;
mysql auto_increment 초기화
-- 데이터가 없는 상태에서 실행해야
ALTER TABLE shop.items AUTO_INCREMENT=1;
SET @COUNT = 0;
UPDATE shop.items SET shop.items.item_id = @COUNT:=@COUNT+1;