Intro

  • 스프링의 핵심 = 객체지향 & 테스트
  • 테스트 = 의도했던 대로 코드가 동작하는지를 확인해서, 만든 코드를 확신할 수 있게 해주는 작업임.

2.1 UserDaoTest 다시 보기

2.1.2 UserDaoTest의 특징

작은 단위의 테스트

  • 테스트하고자 하는 대상이 명확하면 대상에만 집중해서 테스트하는 것이 바람직함.

→ 테스트는 작은 단위로 쪼개서 집중 (관심사의 분리)

→ 단위 테스트(unit test)

자동수행 테스트 코드

  • 테스트는 자동으로 수행되도록 코드로 만들어지는 것이 중요함. (자주 반복할 수 있다는 장점이 있음.)

2.1.3 UserDaoTest의 문제점

  • 수동 확인 작업의 번거로움
    • 테스트의 수행은 코드에의해 자동으로 진행되지만 확인하는 일은 사람의 책임.
  • 실행 작업의 번거로움
    • main() 메소드 이용하는 것보다 편리하고 체계적인 방법 필요함.

2.2 UserDaoTest 개선

2.2.1 테스트 검증의 자동화

  • 테스트 실패
    • 테스트 에러 : 에러가 발생해서 실패
    • 테스트 실패 : 에러가 발생하진 않지만 기대한 답이 아님
  • 빠르게 실행 가능하고 스스로 테스트 수행과 기대하는 결과에 대한 확인까지 해주는 코드로된 자동화된 테스트 만들어두는 것이 좋음.

2.2.2 테스트의 효율적인 수행과 결과 관리

  • 실용적인 테스트를 위한 도구 - JUnit 프레임워크
  • JUnit 프레임워크 요구 조건
    • 메소드가 public으로 선언되어야 함.
    • 메소드에 @Test 추가

2.3 개발자를 위한 테스팅 프레임워크 JUnit

  • 스프링 학습을 위해서는 최소한의 JUnit 테스트 작성 & 실행 방법 알아야 함.

2.3.1 JUnit 테스트 실행 방법

IDE

  • @Test가 들어있는 테스트 클래스 선택 → eclipse run 메뉴의 JUnit Test 선택

2.3.3 포괄적인 테스트

  • JUnit은 하나의 클래스 안에 여러 개의 테스트 메소드가 들어가는 것을 허용함.
    • @Test 붙어있고 public 접근자가 있으며 리턴 값이 void형이고 파라미터가 없다는 조건 지키면 됨.
  • JUnit은 특정한 테스트 메소드의 실행 순서를 보장하지 않음. (테스트 결과가 실행 순서에 영향을 받는다면 테스트를 잘못 만든 것임.)
  • 테스트를 작성할 때 부정적인 케이스를 먼저 만드는 것이 좋음.

2.3.4 테스트가 이끄는 개발

기능설계를 위한 테스트

  • 기능설계, 구현, 테스트라는 일반적인 개발 흐름의 기능설계에 해당하는 부분을 이 테스트 코드가 일부분 담당하고 있다고 볼 수 있음.

테스트 주도 개발(TDD, Test Driven Development)

  • 만들고자 하는 기능의 내용을 담고 있으면서 만들어진 코드를 검증도 해줄 수 있도록 테스트 코드를 먼저 만들고, 테스트를 성공하게 해주는 코드를 작성하는 방식의 개발 방법
  • TDD의 기본 원칙 - 실패한 테스트를 성공시키기 위한 목적이 아닌 코드는 만들지 않는다
  • TDD에서는 테스즈 작성하고 코드를 만드는 작업의 주기를 짧게하는 것을 권장함

2.3.5 테스트 코드 개선

Junit의 테스트 수행 방식

    1. 테스트 클래스에서 @Test가 붙은 public이고 void형이며 파라미터가 없는 테스트 메소드를 모두 찾음.
    1. 테스트 클래스의 오브젝트를 하나 만든다.
    1. @Before 메소드 있으면 실행
    1. @Test 메소드 하나 호출하고 테스트 결과 저장
    1. @After 메소드 있으면 실행
    1. 나머지 테스트 메소드에 대해 2~5번 반복
    1. 모든 테스트의 결과를 종합해서 돌려줌
  • 각 테스트 메소드 실행시마다 테스트 클래스의 오브젝트를 새로 만든다.

    • 왜일까? JUnit 개발자는 각 테스트가 서로 영향을 주지 않고 독립적으로 실행됨을 보장해주기 위해서 매번 새로운 오브젝트를 만들게 함.

픽스처(fixture)

  • 테스트를 수행하는 데 필요한 정보나 오브젝트

2.4 스프링 테스트 적용

  • 애플리케이션 생성 방식
    • 빈이 많아지고 복잡해지면 애플리케이션 컨텍스트 생성에 적지 않은 시간이 걸릴 수 있음.
    • 애플리케이션 컨텍스트가 초기화될 때 어떤 빈은 독자적으로 많은 리소스를 할당하거나 독립적인 스레드를 띄우기도 함.
  • 애플리케이션 컨텍스트 처럼 생성에 많은 자원이 소모되는 경우 테스트 전체가 공유하는 오브젝트 생성함.
  • JUnit은 @BeforeClass 스태틱 메소드를 지원함.
    • 이 메소드에서 애플리케이션 컨텍스트를 만들어 스태틱 변수에 저장해두고 테스트 메소드에서 사용하게 할 수 있음.
    • 스프링이 제공하는 애플리케이션 컨텍스트 테스트 지원 기능이 더 편리함.

2.4.1 테스트를 위한 애플리케이션 컨텍스트 관리

  • 스프링은 JUnit을 이용하는 테스트 컨텍스트 프레임워크를 제공함.

스프링 테스트 컨텍스트 프레임워크 적용

  • @Autowired
  • @RunWith - 스프링의 테스트 컨텍스트 프레임워크의 Junit 확장기능 지정
  • @ContextConfiguration - 테스트 컨텍스트가 자동으로 만들어줄 애플리케이션 컨텍스트의 위치 지정

테스트 메소드의 컨텍스트 공유

  • JUnit은 테스트 메소드 실행시마다 새로운 테스트 오브젝트 생성

→ context 변수에 어떻게 애플리케이션 컨텍스트가 들어있을까?

→ 스프링의 JUnit 확장기능은 테스트가 실행되기 전에 딱 한 번만 애플리케이션 컨텍스트를 만들어두고, 테스트 오브젝트가 만들어질 때마다 특별한 방법을 이용해 애플리케이션 컨텍스트 자신을 테스트 오브젝트의 특정 필드에 주입해주는 것임.

→ 스프링이 애플리케이션 컨텍스트 개수에 상관없이 한 번만 만들어서 공유해줬기 때문에 테스트 수행 속도 빨라짐.

테스트 클래스의 컨텍스트 공유

  • 스프링은 테스트 클래스 사이에서도 애플리케이션 컨텍스트를 공유하게 해준다.
  • @Autowired가 붙은 인스턴스 변수가 있으면, 테스트 컨텍스트 프레임워크는 변수 타입과 일치하는 컨텍스트 내의 빈을 찾음.
    • 타입이 일치하는 빈이 있으면 인스턴스 변수에 주입.
    • 별도의 DI 설정 없이 필드의 타입 정보를 이용해 빈을 자동으로 가져올 수 있음. → 타입에 의한 자동와이어링
    • 변수에 할당 가능한 타입을 가진 빈을 자동으로 찾음.
  • 테스트에서도 가능한 한 인터페이스를 사용해서 애플리케이션 코드와 느슨하게 연결해두는 편이 좋음.

2.4.2 DI와 테스트

  • 인터페이스를 두고 DI를 적용해야 하는 이유
      1. 소프트웨어 개발에서 절대로 바뀌지 않는 것은 없다.
      1. 클래스의 구현 방식은 바뀌지 않는다고 하더라도 인터페이스를 두고 DI를 적용하게 해두면 다른 차원의 서비스 기능을 도입할 수 있음.
      1. 효율적인 테스트를 만들기 위해서임.

테스트 코드에 의한 DI

  • @DirtiesContext - 스프링의 테스트 컨텍스트 프레임워크에게 해당 클래스의 테스트에서 애플리케이션 컨텍스트의 상태를 변경한다는 것을 알려줌.

DI를 이용한 테스트 방법 선택

  • 항상 스프링 컨테이너 없이 테스트할 수 있는 방법을 최우선으로
  • 여러 오브젝트와 복잡한 의존관계를 갖고 있는 오브젝트 테스트

→ 스프링의 설정을 이용한 DI 방식의 테스트

2.5 학습 테스트로 배우는 스프링

  • 학습 테스트(learning test)
  • 학습테스트의 목적은 자신이 사용할 API나 프레임워크의 기능을 테스트로 보면서 사용법 익히는 것.

2.5.1 학습 테스트의 장점

  • 다양한 조건에 따른 기능을 손쉽게 확인
  • 프레임워크나 제품을 업그레이드할 때 호환성 검증 도와줌.
  • 테스트 작성에 대한 좋은 훈련
  • 새로운 기술을 공부하는 과정이 즐거워짐
    • 스프링 학습 테스트를 만들 때 참고할 수 있는 좋은 소스는 스프링 자신에 대한 테스트 코드임.

2.5.3 버그 테스트(bug test)

  • 코드에 오류가 있을 때 그 오류를 가장 잘 드러내줄 수 있는 테스트
  • 버그테스트는 실패하도록 만들어야 함.
  • 테스트 방법
    • 동등분할 - 같은 결과를 내는 값의 범위를 구분해서 각 대표값으로 테스트
    • 경계값 분석 - 에러는 동등분할 범위의 경계에서 주로 발생. 경계의 근처에 있는 값을 이용해 테스트하는 방법임.

참고 자료