Spring | 단위 테스트(Unit Test) & 통합 테스트 (Integration Test)

바다·2024년 6월 17일
0

Spring

목록 보기
12/13
post-thumbnail

1. 단위 테스트와 통합 테스트

단위 테스트 [Unit Test]

단위 테스트는 하나의 모듈을 기준으로 독립적으로 진행되는 가장 작은 단위의 테스트이다. 여기서 모듈은 어플리케이션에서 작동하는 하나의 기능 또는 메소드이다.

즉, 단위 테스트는 어플리케이션으 구성하는 하나의 기능이 올바르게 동작하는지를 독립적으로 테스트하는 것이다. "어떤 기능이 실행되면 어떤 결과가 나온다" 정도를 테스트를 통해 검증한다.

통합 테스트 [Integration Test]

통합 테스트는 모듈을 통합하는 과정에서 모듈 간의 호환성을 확인하기 위해 수행되는 테스트이다. 일반적으로 어플리케이션은 여러 개의 모듈로 구성되어 있고, 모듈들이 메시지를 주고 받으면서 기능을 수행한다.

그렇기에 통합된 모듈들이 올바르게 연계되어 동작하는지 검증이 필요한데, 이러한 목적으로 진행되는 테스트가 통합 테스트이다.


2. 단위 테스트

1) 장점

  • 격리된 환경에서 개별적인 코드 단위를 테스트 하기 때문에, 디버깅과 문제 해결이 쉽다
  • 코드의 특정 기능을 독립적으로 검증하므로 코드의 신뢰성을 높인다
  • 각각의 메소드만 확인하면 되기 때문에 실행이 빠르다

2) 단점

  • 단위 테스트는 각각의 메소드를 테스트하는 데 초점을 맞추기 때문에 복잡한 상효작용을 다루는 데 한계가 있다
  • 개별 메소드의 오류를 발견하는 데에는 유용하지만, 전체 시스템의 동작이나 성능 문제를 발견하는 데는 한계가 있다

3) Spring에서의 단위 테스트

스프링에서는 @Mock (모의 객체) 을 사용하여 다른 레이어와 분리된 단위 테스트를 진행할 수 있다.

유저 테스트 예시

@ExtendWith(MockitoExtension.class)
class UserServiceTest {
	@Mock
	UserRepository userRepository;
	
	@Mock
	PasswordEncoder passwordEncoder;
	
	@Mock
	JwtUtil jwtUtil;
	
	@InjectMocks
	UserService userService;
	
	@Test
	@DisplayName("회원가입 성공")
	void 회원가입성공() {
		//given
		UserRequestDTO userRequestDTO = createUserRequestDTO();
		
		when(userRepository.findByUserId(anyString())).thenReturn(Optional.empty());
		when(userRepository.findByEmail(anyString())).thenReturn(Optional.empty());
		when(passwordEncoder.encode(anyString())).thenReturn("encodedPassword");

		User user = User.builder()
			.userId(userRequestDTO.getUserId())
			.password("encodedPassword")
			.name(userRequestDTO.getName())
			.email(userRequestDTO.getEmail())
			.userType(UserType.UNVERIFIED)
			.introduce(userRequestDTO.getIntroduce())
			.build();

		when(userRepository.save(Mockito.any(User.class))).thenReturn(user);
		
		//when
		UserResponseDTO responseDTO = userService.createUser(userRequestDTO);
		
		//then
		assertThat(responseDTO).isNotNull();
		assertThat(responseDTO.getUserId()).isEqualTo(userRequestDTO.getUserId());
		assertThat(responseDTO.getName()).isEqualTo(userRequestDTO.getName());
		assertThat(responseDTO.getEmail()).isEqualTo(userRequestDTO.getEmail());
		assertThat(responseDTO.getIntroduce()).isEqualTo(userRequestDTO.getIntroduce());
	}
	
	@Test
	@DisplayName("회원가입 실패 - 이미 존재하는 아이디")        
	void 회원가입실패_존재하는아이디() {
	    //given
		UserRequestDTO userRequestDTO = createUserRequestDTO();
	    when(userRepository.findByUserId(anyString())).thenReturn(Optional.of(User.builder().build()));
		
	    //when - then
		assertThatThrownBy(() -> userService.createUser(userRequestDTO))
			.isInstanceOf(UserException.class)
			.hasMessageContaining("중복된 id 입니다.");
	}
	
	@Test
	@DisplayName("회원가입 실패 - 이미 존재하는 이메일")
	void 회원가입실패_존재하는이메일() {
	    //given
		UserRequestDTO userRequestDTO = createUserRequestDTO();
		when(userRepository.findByUserId(anyString())).thenReturn(Optional.empty());
		when(userRepository.findByEmail(anyString())).thenReturn(Optional.of(User.builder().build()));
		
		//when - then
	    assertThatThrownBy(() -> userService.createUser(userRequestDTO))
			.isInstanceOf(UserException.class)
			.hasMessageContaining("중복된 Email 입니다.");
	}

3. 통합 테스트

1) 장점

  • 여러 모듈이 함께 동작하는 방식과 통합 되었을 때 발생할 수 있는 문제를 발견할 수 있다
  • 실제 운영 환경과 유사한 환경에서 테스트가 진행되기 때문에 사용자 관점에서 시스템을 테스트할 수 있다
  • DB나 외부 API 등과 같은 외부 종속성과의 상호작용을 테스트할 수 있다

2) 단점

  • 많은 모듈과 외부 종속성을 포함하기 때문에 실행 시간이 길어진다
  • 문제가 발생했을 때 정확한 원인을 파악하기 어려울 수 있다
  • 통합 테스트는 시스템 전체를 검증하는 것에 중점을 두기 때문에, 개별 메소드의 세부적인 오류를 놓칠 수 있다

3) Spring에서의 통합 테스트

스프링에서는@SpringBootTest 어노테이션을 통해 직접 스프링 콘테이너를 띄우고 Bean을 주입 받아서 테스트를 진행할 수 있다

유저 테스트 예시

@SpringBootTest
@Transactional
@ActiveProfiles("test")
class UserServiceTest {
	@Autowired
	UserService userService;
	
	@Autowired
	private UserRepository userRepository;
	
	@Test
	@DisplayName("유저 생성 성공 테스트")
	void 유저생성성공() {
	    //given
		UserRequestDTO requestDTO = new UserRequestDTO();
		requestDTO.setUserId("heesue");
		requestDTO.setName("test");
		requestDTO.setPassword("test");
		requestDTO.setEmail("12123@gmail.com");
		requestDTO.setIntroduce("test");
		
	    //when
		UserResponseDTO responseDTO = userService.createUser(requestDTO);
		
		//then
		assertThat(responseDTO.getUserId()).isEqualTo(requestDTO.getUserId());
		assertThat(responseDTO.getName()).isEqualTo(requestDTO.getName());
		assertThat(responseDTO.getEmail()).isEqualTo(requestDTO.getEmail());
		assertThat(responseDTO.getIntroduce()).isEqualTo(requestDTO.getIntroduce());
	}
	
	@Test
	@DisplayName("유저 생성 실패 테스트 - 중복된 아이디")
	void 유저생성실패_중복된아이디() {
	    //given
	    UserRequestDTO requestDTO = MonkeyUtils.commonMonkey().giveMeOne(UserRequestDTO.class);
		requestDTO.setUserId("test");
		
	    //when
	    assertThatThrownBy(() -> userService.createUser(requestDTO))
			.isInstanceOf(UserException.class);
	}
	
	
	@Test
	@DisplayName("유저 생성 실패 테스트 - 중복된 이메일")
	void 유저생성실패_중복된이메일() {
	    //given
		UserRequestDTO requestDTO = MonkeyUtils.commonMonkey().giveMeOne(UserRequestDTO.class);
		requestDTO.setEmail("test@gmail.com");
		
	    //when - then
		assertThatThrownBy(() -> userService.createUser(requestDTO))
			.isInstanceOf(UserException.class);
	}
profile
ᴘʜɪʟɪᴘᴘɪᴀɴs 3:14

0개의 댓글