입사 후 공부하며 기술 스텍을 쌓던 내게 던져진 첫 실무 과제.
stack : Springboot 2.3.6 RELEASE, gradle, JPA, mysql ...
저번시간에 이어 이번에는 test
코드를 작성해보자.
서비스가 커지고, 로직이 복잡해질 수록 TEST
코드의 정밀함은 매우 중요하다.
나도 실무를 시작하면서 TDD
의 중요성을 실감하고 있다.
TDD
:Test-Driven Development
즉, 테스트 주도 개발을 의미 🤔
실무는 더 이상 Hello world
만 출력하는 수준의 코딩이 아니다.
Sub module
, MSA
등의 개념들이 들어가고 코드량이 많아지면 분명 내가 만든 건데도 헷갈릴때가 많다.
그렇기 때문에, 핵심 로직을 통과하기 위한 최소한의 데이터와 코드를 생성하여 테스트 하며 정교하게 비지니스 로직들을 디버깅하고, 문제를 발견하는 작업이 매우 중요하다.
테스트 주도의 설계를 하면 핵심로직을 짜기 전, 미리 테스트를 해볼수 있고 설계를 수정 한 후에 핵심 로직 개발을 들어갈 수 있기 때문에 발생되는 문제와 설계 오류를 쉽게 잡을 수 있다.
사실 아직 나도 TDD
가 낯설다 현실은 개발하고 테스트하고 있다.
엄밀히 말해, 지금 진행하고 있는 카테고리 구현에서 테스트 코드를 작성하는 시점이 TDD
라고 말하기는 어렵다. 핵심 로직을 대충 거의 만들어 놓고, TEST
를 구현하고 있기 때문인데, 이후 Refactor
작업에서 핵심 비지니스로직을 완성할 것이기 때문에... 봐주세요
IntelliJ
를 사용하고 있다면, 매우 쉽게 TEST
코드의 뼈대를 잡아줄 수 있다.테스트 코드는 JUnit5
로 진행하였다.
테스트를 진행하기위해 필요한 의존성과, 반복되는 작업을 줄여주는 method
코드를 보자.
@SpringBootTest
@Transactional
class CategoryServiceTest {
@Autowired
CategoryService categoryService;
@Autowired
CategoryRepository categoryRepository;
//SavedID
private CategoryDTO createCategoryDTO(String testBranch, String testCode, String testName) {
CategoryDTO categoryDTO = new CategoryDTO();
categoryDTO.setBranch(testBranch);
categoryDTO.setCode(testCode);
categoryDTO.setName(testName);
return categoryDTO;
}
//Find Category
private Category findCategory (Long savedId) {
return categoryRepository.findById(savedId).orElseThrow(IllegalArgumentException::new);
}
SpringBootTest
어노테이션은 Junit5
환경에서 테스트를 하기위해 필요한 필수 어노테이션이다.
@transactional
어노테이션은 테스트 코드내에서 각각의 테스트들이 하나의 transaction
으로 관리 할 수 있도록 해준다. 즉, 하나의 테스트가 끝나면 테스트 코드들의 데이터들을 DB
에서 rollback
해주기 때문에, 테스트가 온전히 그 자체만으로 데이터 훼손 없이 일어날 수 있게 된다.
@Autowired
어노테이션을 통해 Spring
이 bean
으로 등록한 CategoryService
와 CategoryRepository
를 주입 받는다.
createCategoryDTO()
는 밑에 테스트에서 반복되는 코드를 줄이기 위해 호출해서 간편히 쓰려구 만들었다.
findCategory()
도 마찬가지.
코드 간편화와 반복작업을 줄이는 것은 개발자의 숙명. 개발자는 게을러야해
나는 주로 테스트 코드의 메서드 이름을 한글로 적는 편이다.
그게 가독성도 좋고, 어떤걸 테스트하고 있는지 확실히 알수 있어서 좋다.
@Test
public void 카테고리_저장_테스트 () {
//given
CategoryDTO categoryDTO = createCategoryDTO("TestBranch", "TestCode", "TestName");
Long savedId = categoryService.saveCategory(categoryDTO);
//when
Category category = findCategory(savedId);
//then
assertThat(category.getCode()).isEqualTo("TestCode");
}
사실, 테스트코드는 너무 간단하다.
DTO
를 만들고, 그 DTO
객체를 테스트할 categoryService.saveCategory()
메소드에 파라미터로 넘겨줘서 테스트해준다.
🖍 assertThat
메소드는 테스트 코드의 핵심이다.
import static org.assertj.core.api.Assertions.*;
Junit5
를 통해 생성된 테스트의 Assertions
는 org.junit.jupiter.api.Assertions.*;
를 static
으로 import
를 한다. 이것과 다른 assertj
의 Assertions
를 사용하여 테스트 했다.업데이트 테스트를 위해서는 테스트 데이터를 테스트 DB
에 저장을 해야하고, 그 저장한 데이터를 다시 꺼내와서 target
객체를 가지고 요리해줘야 한다.
개발자는 코드를 봐야 이해가 빠르다. 코드를 보자.
@Test
public void 카테고리_업데이트_테스트 () {
//given
CategoryDTO categoryDTO = createCategoryDTO("TestBranch", "TestCode", "TestName");
Long savedId = categoryService.saveCategory(categoryDTO);
Category category = findCategory(savedId);
CategoryDTO targetCategory = new CategoryDTO(category);
targetCategory.setName("UpdateCategory");
//when
Long updateId = categoryService.updateCategory("TestBranch", "TestCode", targetCategory);
Category updatedCategory = findCategory(updateId);
//then
assertThat(updatedCategory.getName()).isEqualTo("UpdateCategory");
}
업데이트도 매우 간단하다.
가져온 targetCategory
객체를 setter
를 통해 name
을 바꿔줬다.
(현재 요구되는 스펙이 일단은 name
필드만 수정하게 만들어놓았기 때문이다.)
assertThat
을 사용해 볼것이다. @Test
public void 카테고리_삭제_테스트 () {
//given
CategoryDTO categoryDTO = createCategoryDTO("TestBranch", "TestCode", "TestName");
Long savedId = categoryService.saveCategory(categoryDTO);
//when
categoryService.deleteCategoryOld(savedId);
//then
IllegalArgumentException e =
assertThrows(IllegalArgumentException.class,
() -> categoryService.findCategory(savedId));
assertThat(e.getMessage()).isEqualTo("찾는 카테고리 없습니다.");
}
IllegalArgumentException
객체를 만들고, assertThrows
를 사용하여 findCategory()
에서 예외를 발생시키고, e
라는 변수에 그 예외를 저장했다.
e.getMessage()
를 findCategory()
에서 예외가 터질때 출력하도록 만든 메세지와 비교하여 예외가 제대로 터졌는지 비교했다.
IntelliJ
우측에Gradle
을 통해서 열어보면test
를 확인할 수 있다.- 이걸 더블클릭하면 모든
test
들이 실행된다.- 만약 하나의
test
만 실행하고 싶다면, 실행하고 싶은test
메소드만 실행하면 된다.
- 이렇게 초록색으로 좌르륵 테스트가 통과될때가 기분이 정말 좋다.
TDD
는 개발자가 꼭 가져야 할 습관인 것 같다.
TEST
코드를 정교하고 정밀하게 짜놓으면 개발이 더 쉽고 즐거워진다.
다음 포스팅에서는 api
통신을 반환하기 위한 controller
와 Refactor
작업을 다루도록 하겠다.
요구 스펙이 또 변해서... Refactor
를 해야한다