본문 바로가기

토비의 스프링 정리

토비의 스프링 - 2.5 학습 테스트로 배우는 스프링

2.5.1 학습 테스트(Learning Test)

  • 자신이 만들지 않은 프레임워크나 라이브러리 등의 테스트를 작성하는 것
  • 자신이 사용할 API나 프레임워크의 기능을 테스트로 보면서 사용법을 익힘
  • 프레임워크등 기능 검증 목적이 아님. 개발자의 이해도와 사용 방법을 검증하는 것임
  • 학습 테스트를 통해 잘못된 지식이 바로잡기도 함
  • 테스트 대상보다 테스트 코드 자체에 관심을 가져야 함

2.5.2 학습 테스트의 장점

  1. 다양한 조건에 따른 기능을 손쉽게 확인해 볼 수 있음
    • 예제를 만들면서 학습을 하는것은 수동 테스트와 성격이 비슷함
    • 반면에 학습 테스트는 자동화된 테스트 코드로 만들어지기 때문에 다양한 조건에 따라 기능이 어떻게 동작하는지 빠르게 확인 할 수 있음
  2. 학습 테스트 코드를 개발 중에 참고할 수 있음
    • 수동 테스트는 최종적으로 수정한 예제 코드만 남음
    • 학습 테스트를 통한 자동화된 테스트 코드는 다양한 기능과 조건에 대한 테스트 코드를 개별적으로 만들고 남겨둘 수 있음
  3. 프레임워크나 제품을 업그레이드할 때 호환성 검증을 도와줌
    • 자주 사용하는 기능에 대한 테스트를 만들어 놓으면 새로운 버전의 프레임워크나 제품을 학습 테스트에 먼저 적용하여 호환성을 확인할 수 있음
    • 애플리케이션 개발에 사용하는 주요 기능에 대한 학습 테스트를 만들어 놓으면 API의 변경 사항에 맞춰 발빠르게 대응할 수 있음
  4. 테스트 작성에대한 좋은 훈련이 됨
    • 학습 테스트를 작성해보면서 테스트 코드 작성을 연습할 수 있음
    • 프레임워크의 학습 테스트는 실제 프레임워크를 사용하는 애플리케이션 코드의 테스트와 비슷하게 만들어지기 때문
    • 학습 테스트는 한, 두 가지 간단 기능에만 초점을 맞추면 되기 때문에 테스트도 대체적으로 단순함
  5. 새로운 기술을 공부하는 과정이 즐거워짐
    • 테스트 코드를 만들면서 하는 학습은 흥미와 재미를 느낄 수 있음

💡 학습 테스트는 새로운 프레임워크나 기술을 전반적으로 공부하는데 유용함. 책의 저자인 토비 역시 새로운 프레임워크를 공부할 때 학습 테스트를 먼저 작성함

 

2.5.3 JUnit 테스트 오브젝트 테스트

  • JUnit으로 만드는 JUnit 자신에 대한 테스트를 할 것임
  • JUnit 테스트 메소드를 수핼할 때마다 새로운 오브젝트를 생성하는 것을 확인
  • is(not())은 is()와 반대로 같지 않아야 테스트 성공
  • sameInstance()는 실제로 같은 오브젝트인지 비교
  • 하지만 밑의 코드는 직전의 오브젝트만을 비교하므로, 첫 번째와 세 번째가 같을 수도 있는 경우 검증 못함
import org.junit.Test;
import static org.hamcrest.CoreMatchers.*;
import static org.junit.Assert.assertThat;

public class JUnitTest {
    static JUnitTest testObject;

    @Test
    public void test1(){
        assertThat(this, is(not(sameInstance(testObject))));
        testObject = this;
    }

    @Test
    public void test2(){
        assertThat(this, is(not(sameInstance(testObject))));
        testObject = this;
    }

    @Test
    public void test3(){
        assertThat(this, is(not(sameInstance(testObject))));
        testObject = this;
    }
}
  • 컬렉션을 통해 해당 문제를 해결
  • 컬렉션 Set에 오브젝트를 저장하고, not(hasItem())으로 새로 생성된 오브젝트와 저장된 오브젝트 일치 여부 비교
public class JUnitTest {
    static Set<JUnitTest> testObject = new HashSet<>();

    @Test
    public void test1(){
        assertThat(testObject, not(hasItem(this)));
        testObject.add(this);
    }

    @Test
    public void test2(){
        assertThat(testObject, not(hasItem(this)));
        testObject.add(this);
    }

    @Test
    public void test3(){
        assertThat(testObject, not(hasItem(this)));
        testObject.add(this);
    }
}

2.5.4 스프링 테스트 컨텍스트 테스트

  • 모든 테스트 메소드가 하나의 애플리케이션 컨텍스트를 공유하는지 확인
  • 설정파일에 bean이 없어도 되는 이유는, DI를 확인하는 것이 아닌 애플리케이션 컨텍스트가 만들어지는 방식을 확인하는 것이기 때문
  • 매번 동일한 애플리케이션 컨텍스트가 context 변수에 주입됐는지 확인
  • 매번 null을 확인하는 이유는 첫 번째 테스트실행 시에는 contextObect에 값이 주입되지 않았으므로 null이기 때문
  • 각 메소드마다 다른 방법으로 비교하지만 결과는 같음
//junit.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
                            http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
</beans>

//JUnitTest.java
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "/junit.xml")
public class JUnitTest {
    @Autowired
    ApplicationContext context;

    static Set<JUnitTest> testObject = new HashSet<>();
    static ApplicationContext contextObject = null;

    @Test
    public void test1() {
        ...
        assertThat(contextObject == null || contextObject == this.context, is(true));
        contextObject = this.context;
    }

    @Test
    public void test2() {
        ...
        assertTrue(contextObject == null || contextObject == this.context);
        contextObject = this.context;
    }

    @Test
    public void test3() {
        ...
        assertThat(contextObject, either(is(nullValue())).or(is(this.context)));
        contextObject = this.context;
    }
}

2.5.5 버그 테스트(Bug Test)

  • 코드에 오류가 있을 때, 해당 오류를 잘 드러내줄 수 있는 테스트
  • 버그 테스트는 일단 실패하도록 만들어야 함
  • 장점
    1. 테스트의 완성도를 높여줌
      • 기존 테스트에서 미처 검증하지 못했던 부분을 찾을 수 있음
      • 불충분 했던 부분 보완
    2. 버그 내용을 명확하게 분석할 수 있음
      • 실패를 위한 버그 테스트를 만들기 위해서는 어떤 이유 때문에 문제가 생겼는지 명확하게 알아야 함
      • 다른 오류도 찾을 수 있음
    3. 기술적인 문제를 해결하는 데 도움됨
      • 버그 원인을 찾기 어렵거나, 기술적인 문제가 있는 문에를 버그 발생 단순 코드와 드에대한 버그 테스트를 만들면 도움됨

2.5.6 동등 분할과 경계값 분석

  1. 동등 분할(Equivalence Partitioning)
    • 같은 결과를 내는 값의 범위를 구분해서 각 대표 값으로 테스트
  2. 경계값 분석(Boundary Value Analysis)
    • 에러는 동등분할 범위의 경계에서 주로 많이 발생하는 특징을 이용해 경계 근처의 값을 이용한 테스트
    • 보통 숫자의 경우 0, 0의 주변 값, 정수의 최댓값, 정수의 최솟값 등이 가장 많이 도움됨