Junit5를 통한 테스트

안승섭·2023년 2월 4일
1

경험들

목록 보기
1/7

취업에 성공한 후...

입사 후 경험들을 담으려 이 글을 시작으로 다시 블로그를 시작하려 한다
이 글부터는 OJT에서 Junit5을 사용한 경험을 적겠다

Junit이란 무엇인가

Junit이란 이름에서 유추할 수 있듯이 JVM을 사용하는 기반의 언어에서 테스트를 위해 사용하는 테스팅 프레임워크이다 @Test 어노테이션으로 테스트 메소드를 정의할 수 있으며 assert로 실제 값이 내가 기대한 값과 일치하는지 검증한다

Mock

Mock이란 진짜 객체가 아닌 가짜 객체로 진짜 객체의 동작을 모의로 테스트하기 위해 사용한다. 가령 테스트 하려는 소스가 구글 등 다른 플랫폼의 외부 API를 사용한다고 환경이라면 우리는 테스트 시 매번 외부와 통신하기보단 외부 서비스 없이도 테스트를 진행하도록 모의 객체를 만들어 테스트를 진행하기 위해 사용한다

Junit5 + Mockito

아래 환경에서 given-when-then 패턴으로 테스트를 진행하려고 한다

StudyService

@RequiredArgsConstructor
@Transactional(isolation = Isolation.SERIALIZABLE, rollbackFor = Exception.class)
@Service
public class StudyService {

    private final MemberService memberService;

    private final StudyRepository studyRepository;

    private final StudyMapper studyMapper;

    public StudyResDTO createStudy(StudyReqDTO reqDTO){
        try {
            Optional<Member> member = memberService.findById(reqDTO.getOwner());

            if (member.isEmpty()){
                throw new IllegalArgumentException("There is no memberId " + reqDTO.getOwner());
            }

            Study study = studyMapper.toStudy(reqDTO);

            studyRepository.save(study);

            return studyMapper.toStudyResDTO(study);
        } catch (Exception err){
            err.printStackTrace();
        }
        return null;
    }
}

StudyMapper

@Mapper(componentModel = "spring", injectionStrategy = InjectionStrategy.CONSTRUCTOR,
imports = {
        Member.class
})
public interface StudyMapper {
    StudyMapper INSTANCE = Mappers.getMapper(StudyMapper.class);

    @Mapping(target = "limit", source = "chapter")
    StudyResDTO toStudyResDTO(Study study);

    @Mappings({
            @Mapping(target = "owner", expression = "java(Member.builder().idx(dto.getOwner()).build())"),
            @Mapping(target = "idx", ignore = true),
            @Mapping(target = "chapter", source = "limit")
    })
    Study toStudy(StudyReqDTO dto);
}

MemberService

@RequiredArgsConstructor
@Transactional(isolation = Isolation.SERIALIZABLE, rollbackFor = Exception.class)
@Service
public class MemberService {

    private final MemberRepository memberRepository;

    public Optional<Member> findById(Long Id) {
        return memberRepository.findById(Id);
    }
}

StudyRepository

package me.tmdtjq32.myproject.src.repository;

import me.tmdtjq32.myproject.src.model.entity.Study;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

@Repository
public interface StudyRepository extends JpaRepository<Study,Long> {
}

StudyService에서 우리가 테스트 하려는 건 DB에서 값을 잘 불러오는지가 아니라 Option member가 정상적으로 응답했거나 empty인 경우를 mock을 통해 가정해 우리의 의도대로 코드가 동작하는지가 테스트의 목적이다

StudyServiceTest

@InjectMocks
    StudyService studyService;

    @Mock MemberService memberService;
    @Mock StudyRepository studyRepository;
    @Mock StudyMapper studyMapper;

    @Test
    @DisplayName("createStudy 성공 케이스")
    void createStudy() {
        // given
        StudyReqDTO reqDTO = StudyReqDTO.builder()
                .limit(1)
                .name("study")
                .status(StudyStatus.TODO)
                .owner(1L)
                .build();

        Study study = Study.builder()
                .chapter(reqDTO.getLimit())
                .name(reqDTO.getName())
                .status(reqDTO.getStatus())
                .owner(Member.builder().idx(reqDTO.getOwner()).build())
                .build();

        StudyResDTO resDTO = StudyResDTO.builder()
                .limit(study.getChapter())
                .name(study.getName())
                .status(study.getStatus())
                .build();

        Member member = Member.builder()
                .idx(1L)
                .name("test")
                .email("test@email.com")
                .build();

        when(memberService.findById(reqDTO.getOwner()))
                .thenReturn(Optional.of(member));

        when(studyMapper.toStudy(reqDTO))
                .thenReturn(study);

        when(studyRepository.save(study))
                .thenReturn(study);

        when(studyMapper.toStudyResDTO(study))
                .thenReturn(resDTO);
        // when
        StudyResDTO result = studyService.createStudy(reqDTO);

        // then
        assertAll(
                () -> assertThat(result.getLimit()).as("limit가 일치하지 않습니다").isEqualTo(resDTO.getLimit()),
                () -> assertThat(result.getName()).as("name이 일치하지 않습니다").isEqualTo(resDTO.getName()),
                () -> assertThat(result.getStatus()).as("status가 일치하지 않습니다").isEqualTo(resDTO.getStatus())
        );
    }

아래와 같이 findById 메소드의 응답을 정의 후

when(memberService.findById(reqDTO.getOwner()))
                .thenReturn(Optional.of(member));

createStudy 메소드를 실행했을 때

studyService.createStudy(reqDTO);

우리가 의도한 응답이 나오는지 검증하는 것이다

assertAll(
                () -> assertThat(result.getLimit()).as("limit가 일치하지 않습니다").isEqualTo(resDTO.getLimit()),
                () -> assertThat(result.getName()).as("name이 일치하지 않습니다").isEqualTo(resDTO.getName()),
                () -> assertThat(result.getStatus()).as("status가 일치하지 않습니다").isEqualTo(resDTO.getStatus())
        );
profile
Just Do It!

0개의 댓글