본문 바로가기
개발/WIL

[WIL]TDD 방법론 스터디_통합테스트 코드 구현

by 반비🥰 2024. 5. 10.
반응형

 

항해플러스 사전스터디 기반으로 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

 

반응형