본문으로 건너뛰기
  1. Posts/

Java Web Project Unit Test

·3 분· loading · loading ·
Yna
Techtopic 단위 테스트 Junit Java Test Unit Test
InnoFactory
작성자
InnoFactory
스마트팩토리, 산업자동화, Digital Transformation, 디지털팩토리, PLM, ALM, Digital Manufacturing, Visualization, 3D CAD, Digital Twin, Big Data, IIoT 솔루션 전문업체
작성자
Yeongkyun Na
Developer of Innofactory.

Java Web Project Unit Test
#

프로젝트를 진행하다 보면 단위 테스트를 수행해야 하는 경우가 있습니다. 이 글을 통해 java 언어로 개발 시 단위 테스트를 효율적으로 진행하기 위한 내용을 공유하고자 합니다.

단위 테스트의 목적
#

단위 테스트를 진행할 경우 데이터베이스에 접근하는 것은 일반적으로 권장되지 않습니다. 단위 테스트의 목적은 소프트웨어의 개별적인 구성 요소를 독립적으로 검증하는 것이기 때문에, 외부 시스템에 의존하지 않고 테스트를 수행해야 합니다. 그러나, 특정 경우에 데이터베이스와의 상호작용을 포함하는 로직을 테스트해야 할 필요가 있을 수 있습니다. 여기서는 주로 목 객체(Mock Object)를 사용한 테스트 방법에 대해 설명하겠습니다.

데이터베이스에 접근을 권장하지 않는 이유
#

  1. 속도 문제: 단위 테스트의 핵심 목적 중 하나는 빠른 피드백을 제공하는 것입니다. 데이터베이스에 접근하는 테스트는 네트워크 지연, 데이터베이스 초기화, 데이터 조회 및 삽입 등으로 인해 실행 시간이 길어집니다. 이는 개발자가 지속적으로 코드를 반복하고 빠르게 피드백을 받는 과정을 방해할 수 있습니다.
  2. 환경 의존성: 단위 테스트는 가능한 한 독립적으로 실행될 수 있어야 합니다. 데이터베이스에 접근하게 되면 테스트 환경을 구성하기 위한 추가 작업이 필요하며, 이는 테스트 실행에 대한 외부 의존성을 증가시킵니다. 이러한 의존성은 테스트의 신뢰성을 저하시키고, 다양한 환경에서의 일관된 테스트 실행을 어렵게 만듭니다.
  3. 복잡성 증가: 데이터베이스와의 상호작용을 포함하는 단위 테스트는 테스트의 복잡성을 증가시킵니다. 데이터베이스 상태 관리, 연결 관리, 데이터 정리 등 추가적인 관리 작업이 필요하며, 이는 테스트 코드를 유지보수하기 어렵게 만듭니다.
  4. 격리 문제: 단위 테스트는 테스트되는 코드 단위 외에는 어떤 외부 상태에도 의존해서는 안 됩니다. 데이터베이스를 사용하면 테스트 간 데이터 상태가 공유될 위험이 있으며, 이는 테스트 간의 격리를 보장하기 어렵게 만듭니다. 이로 인해 한 테스트의 실패가 다른 테스트에 영향을 줄 수 있습니다.
  5. 실제 환경과의 차이: 개발 환경의 데이터베이스와 실제 운영 환경의 데이터베이스 간에는 설정, 데이터, 버전 차이가 있을 수 있습니다. 이러한 차이로 인해 개발 중에는 문제가 없어 보이나 실제 환경에 배포했을 때 예기치 않은 문제가 발생할 수 있습니다.

목 객체(Mock Object) 사용하기
#

목 객체는 실제 객체를 흉내 내는 가짜 객체로, 테스트 대상이 되는 코드와 상호작용합니다. 이 방법을 사용하면 실제 데이터베이스에 의존하지 않고도 데이터베이스 호출을 시뮬레이션 할 수 있습니다.

Mockito 라이브러리 사용
#

Maven 의존성 추가
#
<dependency>
    <groupId>org.mockito</groupId>
    <artifactId>mockito-core</artifactId>
    <version>3.x</version>
    <scope>test</scope>
</dependency>
Gradle 의존성 추가
#
dependencies {
    testImplementation 'org.mockito:mockito-core:3.+'
}

버전문제가 있을 경우 https://mvnrepository.com 로 접속하여 현재 개발에 사용되는 버전과 호환이 되는 버전을 찾아서 사용하세요.

Test 작성
#

서비스 인터페이스 목 객체 생성
#

데이터베이스를 사용하는 서비스 인터페이스에 대한 목 객체를 생성합니다.

import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestInstance;
import org.junit.jupiter.api.TestInstance.Lifecycle;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.springframework.boot.test.context.SpringBootTest;

@SpringBootTest
@TestInstance(Lifecycle.PER_CLASS)
public class DemoServiceTest {

	@Mock
	private DemoService demoService;
	
	@BeforeAll
	public void init() {
		MockitoAnnotations.openMocks(this);
	}

}

테스트 케이스 작성
#

목 객체를 사용하여 테스트 케이스를 작성합니다. 특정 메소드 호출이 예상하는 값을 반환하도록 설정할 수 있습니다.

import static org.mockito.Mockito.*;

@Test
public void testMyServiceMethod() {

    // 목 객체에 대한 행동 설정
    when(demoService.getData()).thenReturn("Hello");
    // 테스트 대상 메소드 실행
    String result = demoService.getData();
    // 결과 검증
    assertThat("Hello").isEqualTo(result);

}

결론
#

단위 테스트에 데이터베이스 연결이 권장되지 않는 것과 Mock을 사용하면 된다는 것은 알고 있었으나, 이번에 이유를 찾아보면서 ‘‘왜 그래야 하는가’‘에 대해 알게 되면서 단위 테스트는 꼭 데이터베이스 연결 없이 테스트를 해야겠다고 마음 먹었습니다.

저도 계속 배워나가는 입장이라 틀린 부분이 있을 수 있으나, 이 글을 통해 개발을 처음 접해보시는 분들에게 조금이나마 도움이 되길 바랍니다.

관련 글

Thingworx 테스트 Tip (3) - 브라우저 개발자 도구 네트워크 기능을 이용한 Session 이벤트 제어와 서비스 이벤트 제어
·2 분· loading · loading
Sseung
Solution Thingworx Debug Test
Thingworx Mashup 개발 시 화면간 이동으로 triggering되는 Load 이벤트와 Session에 설정한 사용자 지정 속성의 이벤트, 서비스의 동작에 따른 이벤트의 연쇄작용으로 테스트가 어려운 경우가 있습니다.
Thingworx 테스트 Tip (2) - 브라우저 개발자 도구 콘솔을 통한 Thingworx Session 객체 접근 및 조작
·2 분· loading · loading
Sseung
Solution Thingworx Debug Test
Thingworx Mashup 개발 시 로직의 순서 제어를 위해 Thingworx의 Session에 설정한 사용자 지정 속성의 이벤트를 이용하는 작업이 필요한 경우가 있습니다.
Thingworx 테스트 Tip (1) - 브라우저 개발자 도구 네트워크 기능을 이용한 로직 디버깅
·2 분· loading · loading
Sseung
Solution Thingworx Debug Test
Thingworx Mashup 개발에는 Mashup에 연결된 Thing의 서비스, 세션 변수, UI 간의 이벤트 바인딩으로 로직을 구성하고 서비스 input/output 바인딩의 작업을 필요로 합니다.