도서 및 강의/소프트웨어 테스트 전문가(CSTS) 가이드

3장 소프트웨어 개발 단계와 테스트 - 3.2 컴포넌트 테스트

간쥬 2025. 11. 25. 18:40

3.2 컴포넌트 테스트

  1. 개요
  2. 모의 객체 생성 프레임워크
  3. FIRST 원칙

3.2.1 개요

컴포넌트(단위) 테스트

개별적인 모듈(또는 컴포넌트) 테스트

각 모듈을 구현한 후 수행

컴포넌트를 독립적인 방식으로 테스트 수행

➡️ 단독으로 실행할 수 있는 환경 필요 - 테스트 베드

➡️테스트 환경의 주요 구성 요소 - 테스트 드라이버, 테스트 스텁

 

 

컴포넌트0, 1, 2 은 연결되어 있지만 각각의 컴포넌트는 단독으로 실행하여 테스트 진행

따라서 컴포넌트 0 테스트를 한 후, 컴포넌트 1을 호출하는 것이 아닌 컴포넌트 1의 스텁을 호출하게 됨

마찬가지로 컴포넌트 1도 컴포넌트 0의 호출이 필요한 게 아니라 드라이버 1이 호출하여 테스트 진행함

 

3.2.2 모의 객체 생성 프레임워크

테스트 되는 메소드가 다른 클래스의 객체에 의존할 수 있음 ➡️ 메소드를 고립화하여 테스트하는 것이 불가능

따라서, 절차 지항젹 프로그래밍의 스텁과 같은 모의(Mock) 객체 필요 (*모의 객체는 스텁의 객체 지향 버전이라 할 수 있음)

모의 객체는 수작업으로 만들거나 모의 객체 생성 프레임워크를 이용하여 생성 가능

테스트 케이스는 크게 생성, 동작, 확인 세 부분으로 구성됨

 

예시) Mockito 모의 객체 생성 프레임워크 사용하여 컴포넌트 테스트 수행하는 방법 

interface Account {
    Money balance();
    boolean withdraw(Money m);
    void deposit(Money m);
}
// Account 타입의 모의 객체 생성
@Mock
Account acctMock;

// Foo 객체를 생성하면서 모의 객체(acctMock)를 주입
@InjectMocks
Foo foo;

@Test
public void testPerformInFoo() {
	// @Mock, @InjectMocks를 초기화하여 객체 생성
    1: MockitoAnnotations.initMocks(this);
    
    // balance()가 호출될 시, 850을 반환
    2: when(acctMock.balance()).thenReturn((Money)850);
    
    // perform()호출 -> 동작
    3: foo.perform();
    
    // acctMock의 balance()가 1번 호출되었는지 확인
    4: verify(acctMock, times(1)).balance();
    
    // acctMock의 withdraw()가 1번 호출되었는지 확인
    5: verify(acctMock, times(1)).withdraw((Money)500);
}

// 확인 사항으로 미루어볼 때 perform()에는 balance()와 withdraw()가 각각 1번씩 호출될 것
// Foo 클래스 추측
public class Foo {

    private final Account account;

    // Mockito가 @InjectMocks로 주입할 때 사용하는 생성자
    public Foo(Account account) {
        this.account = account;
    }

    public void perform() {
        account.balance();
        account.withdraw(new Money(500));
    }
}

 

 

모의 객체 분류

 

더미(Dummy)

테스트할 때 객체만 필요하고 해당 객체의 기능은 필요없을 때 사용

더미 객체의 메소드가 호출되면 정상 동작은 수행하지 않고 예외를 던진다

 

테스트 스텁

더미 객체에 단순한 기능성을 작성하며 추가 객체의 특정 상태를 가정해서 특정한 값을 반환하거나 특정한 메시지를 출력

 

테스트 스파이

테스트 대상 클래스와 협력하는 클래스로 가는 출력을 검증하는데 사용

테스트 대상 클래스가 실행되는 동안 특정 협력 클래스로의 호출(또는 호출의 결과)을 잡아내 실행이 끝난 후 정상 호출되었는지 검증

 

가짜(Fake) 객체

실제 협력 클래스의 기능을 대체해야 할 겨우에 사용

실제 협력 클래스의 기능 중 전체나 일부를 훨씬 단순하게 구현

 

3.2.3 FIRST 원칙

컴포넌트 테스트는 다른 테스트보다 쉽게 수행 가능

테스트 수행에 따른 피드백 빠름

결함 발생 부분을 쉽게 식별하여 수정 가능

컴포넌트 테스트를 잘 수행하기 위한 FIRST 원칙

 

Fast

빠르게 수행

테스트 시간이 길면 테스트를 수행하지 않고자 하는 유혹에 빠지기 쉬움

코드에 새로운 기능이 추가될수록 테스트 실행 시간이 증가되어 품질에 영향을 줄 수 있음

 

Isolated

다른 컴포넌트 테스트에 의존하지 않도록 해야함 = 컴포넌트 테스트 하나를 독립적으로 수행

다른 컴포넌트의 수행 결과에 의존한다면 테스트 실행 순서에 따라 다른 결과가 나올 수도 있기 때문

전체 컴포넌트 테스트 집합을 실행한 결과와 개별적으로 컴포넌트 테스트를 실행한 결과가 달라서는 안 됨

 

Repeatable

몇 번 실행해도 동일한 결과 도출해야 함

데이터베이스를 사용하여 테스트할 경우 주의 ➡️ 개발자만 사용할 수 있는 샌드박스 구축해서 테스트 수행하는 것이 좋음

 

Self-Validating

사람의 개입 없이 테스트가 통과되었는지 알 수 있도록 작성

테스트 결과를 사람이 확인하도록 작성하면 많은 시간이 소요될 수 있으며 위험도 따름

테스트에 필요한 데이터 준비 및 설정도 자동화하여 사람의 개입을 최소화하는 것이 좋음

 

Timely

제때 수행 = 코드가 작성되는 시점에 수행