spring boot 에서 Testcode작성하기

김태훈·2023년 9월 27일

spring boot

목록 보기
6/6

1. test코드의 필요성

프로젝트를 할때 기본적으로 들어가는 기능인 회원 가입 기능을 만들때 save작업으로 구현을 하게된다. 이때 때로는 회원가입 기능이 정상적으로 되었는지 확인을 하고 싶은 때가 많은데 이때 보통 연결된 데이터 베이스에서 sql 쿼리인 select 문을 사용하는게 일반적이다. 이런 경우에 테스트 코드를 미리 작성을 해서 실행을 시켜보면 회원 가입시 여러개의 정보들이 정상적으로 insert되었는지 확인을 쉽게 할 수 있다. 웹 애플리케이션의 복잡도가 높아질수록 이러한 테스트 코드의 중요성은 매우 높아진다. 오늘은 회원 관리 프로젝트에서의 간단한 CURD 작업들을 테스트하는 테스트 코드의 작성을 알아보자.

2. 회원정보 저장하기

다음은 회원가입 기능을 테스트하는 코드이다. 로그인 기능을 테스트하던 회원가입 기능을 테스트하던지 새로운 더미 회원 정보를 데이터베이스에 삽입하는 작업은 공통적으로 있기때문에 새로운 회원정보를 저장하는 테스트 기능을 따로 메서드로 만들어 놓는다.

//회원 가입용 메서드 정의
    private MemberDTO newMember(int i) {
        MemberDTO memberDTO = new MemberDTO();
        memberDTO.setMemberEmail("test_email" + i);
        memberDTO.setMemberPassword("test_pass" + i);
        memberDTO.setMemberName("test_name" + i);
        memberDTO.setMemberBirth("2023-09-27");
        memberDTO.setMemberMobile("010-1111-1111");
    return memberDTO;
    }

3. 다수의 회원정보 저장하기

다음은 위에서 정의한 newMember매서드를 for문으로 여러번 호출해 다수의 더미회원정보를 데이터베이스에 한번에 저장하는 메서드이다. 주석처리한 부분은 일반적인 for문을 사용해서 서비스 클래스의 SAVE메서드를 호출하는 부분이고, 실제로 사용한 부분은 람다식을 사용해서 FOR문을 구현한 것이다.

@Test
//@DisplayName의 값으로 이름을 지정함으로써 콘솔창에 어떤 테스트 케이스를 사용했는지 
//개발자가 명시적으로 알 수 있게 한 것이다. 

    @DisplayName("회원 데이터 붓기")
    public void dataInsert() {
//        for(int i = 1; i<= 20; i++) {
//            MemberDTO memberDTO = newMember(i);
//            memberService.save(memberDTO);
//        }

        IntStream.rangeClosed(1, 20).forEach(i -> {
            //다음 우변의 내용은 처음에 구현해준 newMember(int i)
            //메서드를 호출해 새로운 더미 회원정보를 생성한다.
            MemberDTO memberDTO = newMember(i);
            memberService.save(memberDTO);
        });
    }

4. 회원가입 기능 테스트

다음은 회원가입 기능 테스트를 하는 코드이다.

// 회원가입 기능 테스트
    /*
        1. 새로운 회원을 하나 가입시킴
        2. 가입한 회원의 id 값을 받아옴
        3. 그 id로 조회기능을 실행
        4. 1번에서 만든 회원의 이메일 값과 3번에서
        조회한 이메일 값이 일치하면 테스트 성공
    */
    @Test
    @Transactional
    @Rollback(value = true)
    @DisplayName("회원가입 테스트")
    public void memberSaveTest() {
        // 1.
        MemberDTO newMember = new MemberDTO();
        newMember.setMemberEmail("test_Email");
        newMember.setMemberPassword("test_pass");
        newMember.setMemberName("test_name");
        newMember.setMemberBirth("2023-09-27");
        newMember.setMemberMobile("010-1111-1111");
        //2.
        Long savedId = memberService.save(newMember);
        //3.
        MemberDTO findMember = memberService.findById(savedId);
        // 4. 다음에 Assertions.을 지웠다. static으로 import를 해서.
        assertThat(newMember.getMemberEmail()).isEqualTo(findMember.getMemberEmail());
    }

원래는 assertThat 메서드를 사용시 'Assertions.assertThat'의 형식으로 메서드 호출을 해야한다.
하지만 위 코드에서처럼 assertThat 메서드를 바로 호출을 하고 싶을경우에는 다음과 같이 Assertions를 static으로 import하면 된다.


import static org.assertj.core.api.Assertions.*;

intellij에서 Assertions를 자동완성으로 가져올때는 다음의 사진처럼 가져오면 된다.

Assertions import 대상

5. 로그인 기능 테스트 코드

//로그인 테스트
        /*
        1. 신규 회원 가입
        2. 로그인을 위한 DTO 객체 생성 후 로그인 수행
        3. 로그인 결과 값이 있는지를 통해 성공여부 판단
        * */
    @Test
    @Transactional
    @Rollback(value = true)
    
    //Transactional, Rollback 어노테이션을 사용해서 sava작업을 한뒤 
    //로그인 기능 테스트를 수행한뒤 더미 회원 저장작업을 다시 되돌려 
    //타 기능 테스트시 save작업과 중복이 되어 테스트 실패가 되는 것을 방지한다. 
    
    @DisplayName("로그인 테스트")
    public void loginTest() {
    
        // 1.newMember(999)에서 준 매개변수의 값을 아무 정수값이나 넣어줘도 상괸없다. 
        // 모든 테스트 모듈마다 rollback을 수행하므로 임의의 정수로 매개변수를 주어도 좋다.  
        
        MemberDTO memberDTO = newMember(999);
        memberService.save(memberDTO);
        //2.
        MemberDTO loginMember = new MemberDTO();
        loginMember.setMemberEmail(memberDTO.getMemberEmail());
        loginMember.setMemberPassword(memberDTO.getMemberPassword());
        boolean loginResult = memberService.login(loginMember);
        
        //3.
        //다음에 Assertions.을 지웠다. static으로 import를 해서.
        //Assertions는 스프링 부트와 JUnit과 함께 자주 사용되는 
        //테스트 프레임워크 중 하나이다. 
        //스프링 부트와 JUnit을 통합하여 테스트 코드를 작성하고 
        //테스트 결과를 검증하는 데 사용된다.

		//Assertions는 테스트 코드에서 예상된 결과와 실제 결과를 비교하고,
        //이를 통해 테스트가 성공인지 실패인지를 결정하는 데 도움을 준다.
        //다음의 'assertThat(result).isEqualTo(expected)' 부분 설명 :
        //result: 이 값은 실제로 테스트 중인 코드 또는 메서드의 실행 결과이다. 
        //테스트 코드에서 실행한 특정 작업 또는 함수 호출의 결과가 result로 전달.

		//expected: 이 값은 테스트에서 예상하는 값 또는 기대하는 결과.
        //즉, result와 비교하여 테스트가 성공 또는 실패하는 기준이 되는 값이다.
        assertThat(true).isEqualTo(loginResult);

    }

6. 삭제 기능 테스트

 /*
    * 삭제 기능 테스트
    * 1. 회원가입 수행
    * 2. 회원가입 후 id 받아옴
    * 3. 삭제 기능 수행
    * 4. 삭제 후 해당 id로 조회시  NoSuchElementException 발생
    * */

    @Test
    @Transactional
    @Rollback
    @DisplayName("회원 삭제 테스트")
    public void deleteTest() {
        MemberDTO memberDTO = newMember(9999);
        Long savedId = memberService.save(memberDTO);
        memberService.delete(savedId);
        // 4. 삭제 기능의 테스트를 할때는 저장 처리한 더미 회원정보의 id에 해당하는 정보를 삭제한뒤 해당id를 기준으로 회원 정보가 없어야만 성공적으로 수행된 것이다. 따라서 findById의 리턴 값이 존재하지 않아야하므로 NoSuchElementException.class의 인스턴스인지 확인을 하는 방식으로 테스트 모듈을 작성해야 한다. 
        assertThatThrownBy(() -> memberService.findById(savedId)).isInstanceOf(NoSuchElementException.class);
    }

7. 테스트 모듈의 실행

작성한 테스트 모듈을 실행을 하려면 다음의 사진처럼 매서드 선언 줄의 좌측의 녹색의 실행버튼을 누르면 된다.

테스트 코드 실행 방법

다음은 테스트가 성공적으로 되었을때 콘솔창의 모습이다.

테스트 성공시 콘솔창

다음은 테스트 실패시 콘솔창의 모습이다. 사실 테스트 실패를 하면 빨간색의 오류들이 쏟아져서 누가 봐도 뭔가 잘못되었다는 것을 알수 있다.

테스트 실패시 콘솔창

테스트 모듈들을 성공적으로 실행한 이후 실제 서버에서 기능들을 실행을 하기위해서는 다음 스크린샷에서 보이듯이 자신의 프로젝트 서버를 다시 실행을 해야 한다.

테스트 코드 실행후 서버 실행 방법

구현한 기능들을 테스트하는 모듈을 구현하는 방법을 공부했다. 사실 이 포스팅을 보면서 느꼈겠지만 굳이 테스트 모듈이 필요한가?? 라는 생각이 들수도 있다. 하지만 상당수이상의 기업들은 TDD( Test Driven Development)에 익숙한 개발자들에 대한 수요가 많으므로 테스트 모듈은 익숙해지도록 노력해야할것 같다.

다음은 회원관리 프로젝트의 전체 소스코드가 있는 깃허브 주소이다.

회원관리 프로젝트

0개의 댓글