
항해플러스 사전스터디 기반으로 TDD 코드 내용을 정리한 포스팅입니다.
👩🏻💻TDD 코드 구현
[ 사전 시나리오 ]
- 사용자 관리를 위한 rest api 구축
- 독립적인 개발을 위해 DB연결은 하지 않음
[ 주요 기능 ]
- 사용자 모두 조회
- 특정 사용자 조회
- 사용자 입력
- 사용자 수정
- 사용자 삭제
[ TDD로 사용자 REST API 구현 ]
UserControllerTest.java
@AutoConfigureMockMvc
@SpringBootTest
@RunWith(SpringRunner.class)
public class UserControllerTest {
@Autowired
private MockMvc mockMvc;
@Autowired
private UserRepository userRepository;
@Autowired
ObjectMapper objectMapper;
@BeforeEach
public void insertData() throws Exception {
for(int i =1 ; i<=10; i++){
User user = User.builder()
.userId("아이디"+i)
.userPw("비밀번호"+i)
.userName("이름"+i)
.build();
userRepository.save(user);
}
this.findUserAll();
}
@Test
public void findUserAll() throws Exception{
mockMvc.perform(get("/api/users/findUserAll")
.contentType(MediaType.APPLICATION_JSON_VALUE)
.accept(MediaType.APPLICATION_JSON_VALUE))
.andDo(print())
.andExpect(status().isOk());
}
@Test
public void findUserById() throws Exception{
mockMvc.perform(get("/api/users/아이디1")
.contentType(MediaType.APPLICATION_JSON_VALUE)
.accept(MediaType.APPLICATION_JSON_VALUE))
.andDo(print())
.andExpect(status().isOk());
}
@Test
public void createUser() throws Exception{
User user = User.builder()
.userId("아이디추가")
.userPw("비밀번호추가")
.userName("이름추가")
.build();
mockMvc.perform(post("/api/users/createUser")
.contentType(MediaType.APPLICATION_JSON_VALUE)
.accept(MediaType.APPLICATION_JSON_VALUE)
.content(objectMapper.writeValueAsString(user)))
.andDo(print())
.andExpect(status().isOk())
.andReturn();
}
@Test
public void updateUser() throws Exception{
User user = User.builder()
.userId("아이디수정")
.userPw("비밀번호수정")
.userName("이름수정").build();
mockMvc.perform(put("/api/users/update/아이디3")
.contentType(MediaType.APPLICATION_JSON_VALUE)
.accept(MediaType.APPLICATION_JSON_VALUE)
.content(objectMapper.writeValueAsString(user)))
.andDo(print())
.andExpect(status().isOk());
}
@Test
public void deleteUser() throws Exception{
mockMvc.perform(delete("/api/users/아이디4")
.contentType(MediaType.APPLICATION_JSON_VALUE)
.accept(MediaType.APPLICATION_JSON_VALUE))
.andDo(print())
.andExpect(status().isOk());
this.findUserAll();
}
}
❗️코드 작성 에러
- 통합테스트로 테스트를 진행하면서 단위테스트 어노테이션을 섞어서 사용하였음
➡️ 기본 이론에 대한 지식이 부족
➡️ 통합테스트 어노테이션인 @SpringBootTest와 단위테스트인 @WebMvcTest, @DataJpaTest 어노테이션을 호용하여 사용하여 오류 발생
1) MockMvc 주입 에러
@WebMvcTest 슬라이스 테스트가 아닌 @SpringBootTest는 전체 빈을 메모리에 올리는 테스트로 @AutoConfigureMockMvc를 사용해서 @Service나 @Repository도 같이 메모리에 올림
[ 통합테스트 ]
- spring framework에서 전체적으로 플로우가 제대로 작동하는지 검증하기 위해 사용
- 모든 Bean을 로드하기 때문에 운영환경과 가장 유사한 테스트가 가능
- 테스트 단위가 크기 때문에 속도가 오래 걸림
@SpringBootTest
➡️ Junit4를 사용 시 SpringJunit4ClassRunner 클래스를 상속받는 @RunWith(SpringRunner.class)와 함께 사용
➡️ Junit5 사용시, 해당 어노테이션을 명시할 필요 없음
Mock
- WebAppplicationContext를 로드하며 내장된 서블릿 컨테이너가 아닌 Mock 서블릿 제공
- @AutoConfigureMockMvc 어노테이션을 함께 사용하면 간편하게 MockMvc 테스트 가능
- MockMvc는 브라우저에서 요청과 응답을 의미하는 객체로 Controller 테스트를 용이하게 함
@AutoConfigureMockMvc
➡️MockMvc 객체를 통해 실제 컨테이너가 실행되는 것은 아니지만 로직상으로 테스트 진행 가능
2) @Test import 에러
Cannot invoke "org.springframework.test.web.servlet.MockMvc.perform(org.springframework.test.web.servlet.RequestBuilder)" because "this.mockMvc" is null
Junit5를 사용하고 있으므로 'org.junit.jupiter.api'로 import를 해주어야 오류가 발생하지 않음
3) DB 예약어 오류
org.hibernate.tool.schema.spi.CommandAcceptanceException: Error executing DDL "drop table if exists user cascade " via JDBC [Syntax error in SQL statement "drop table if exists [*]user cascade "; expected "identifier";]
- 데이터베이스 테이블의 이름을 User로 작성해 발생하는 오류로 Dto에 @Table(name="USER")를 추가해 주어 수정 완료
📌 통합테스트를 선택한 이유
단위 테스트는 Service와 Controller 등 각 내부 기능을 테스트하는 것이지만 통합테스트는 모듈 간 상호작용에 중점을 두어 Controller 테스트에 더 적합하다고 생각하여 통합테스트를 진행
➡️ 처음 TDD코드를 짜보는 것이라 단위테스트까지 진행하지 못함
➡️ 다음에는 단위테스트도 같이 진행 예정
GitHub - BoHyun-Choi-0320/tdd-user-service
Contribute to BoHyun-Choi-0320/tdd-user-service development by creating an account on GitHub.
github.com
[Spring Boot] REST API 게시판 서버 만들기 #5(User쪽 적용, 내가 TDD 활용하는 방법.)
프로젝트 구조 - 유저쪽 패키지를 생성합니다. - 컨트롤러와 서비스 DAO단 클래스들을 생성합니다. - 테스트코드에서 User api를 테스트할 클래스를 생성합니다. 파일별 설명 모든 소스는 github에서
sas-study.tistory.com