[데브코스] 소프트웨어 테스팅

Updated: Categories:

W4D1 - 테스팅레벨에 대해 공부하고 단위,통합테스트를 실제로 구현해보자!

소프트웨어 테스팅

테스팅 레벨

  • 단위(Unit) 테스트 : 모듈단위 테스트
  • 통합(Integration) 테스트 : 내부 모듈 간 연동 + 외부 서비스와의 연동을 테스트
  • 시스템(System) 테스트
  • 인수(Acceptance) 테스트 : UI, End to End Test
  • 아래로 갈수록 많은 시간과 노력이 들어가므로, 아래는 테스트 적게 위에는 테스트 많이

image

단위 테스트

  • SUT(System Under Test) : 하나의 클래스라고 생각하면 된다
  • 클래스 단위로 하나씩 고립된 환경에서 테스트를 진행함
  • 다른 객체와 협력관계가 맺어져 있는 경우 실제로 그 객체를 만들지 않고 test double로 대신하게 된다.
  • 지속적인 변경상황에서 테스트를 통해 무결성을 보장받기 위함이다

image

Test Double

  • 테스트 객체와 의존관계가 있는 객체의 역할을 대신해주는 가짜 객체이다.
  • Mock : 행위 검증에 사용한다.
  • Stub : 상태 검증에 사용한다.

image


JUnit

  • 단위 테스트 프레임워크이며, SpringBoot 2.2부터 JUnit 5가 default임
  • 단위 테스트마다 테스트 클래스의 인스턴스가 생성 (독립적 환경)
  • 테스트 라이플 사이클 관리를 위한 어노테이션 제공
  • Assert를 통한 테스트 케이스 수행 결과 판별

JUnit 5

  • Platform : JVM에 테스팅 프레임워크를 실행시키는 엔진
    • Jupitor : 5버전용 엔진의 실제 구현체임. Jupiter API를 사용하여 테스트 코드 작성
    • Vintage : JUnit4로 작성된 테스트 코드 실행시 사용

image


IntelliJ 단위 테스트

  • 클래스명에 alt + enter 누르면 테스트 클래스 생성을 선택할 수 있음
  • 테스트 클래스 생성시 test 패키지에 해당 클래스와 동일한 패키지 구조가 복사되며 만들어짐
  • test 메소드는 항상 void여야 한다.

메소드 Annotation

  • @Test : 테스트 메소드에 달아줌
  • @DisplayName(설명) : 테스트 설명 적기
  • @BeforeAll : 테스트 클래스 실행되자마자 한번 실행
  • @BeforeEach : 테스트 메소드 실행시마다 실행
  • @AfterAll : 테스트 클래스 끝나면 한번 실행
  • @AfterEach : 테스트 메소드가 끝날때마다 실행
    • Before/After 관련 메소드는 static 함수로 작성해야함
  • @Disabled(설명) : 해당 테스트를 건너뛴다
  • @Order(순서) : 테스트 메소드에 순서를 지정
    • 테스트 클래스에 @TestMethodOrder(MethodOrderer.OrderAnnotation.class) 어노테이션을 달아줘야함

Jupiter Assertions Method

  • assertEquals(기대값, 테스트값) : 테스트 결과값이 기대값과 같아야 통과
  • assertThrows(예외 클래스 타입, 잘못된 행위) : 잘못된 행위를 했을때, 적절한 예외 클래스가 발생했는가?

Hamcrest - matcher

  • 컬렉션을 검증해야할 땐 Hamcrest를 사용하는 것이 용이하다.
  • assertThat(테스트값, 검사로직) : 검사로직에 다양한 matcher 메소드를 사용할 수 있음
    • is, hasItem, hasSize, everyItem 등등…

Test Double flow

  • Given : stub/mock 객체를 정의해주고 sut를 생성한다.
  • When : (sut를 사용해 메소드 실행) 테스트할 객체를 생성. (이 행위를 정의)
  • Then : 해당 객체를 가지고 다양한 메소드를 테스트한다.

Stub

  • 상태 검증에 사용된다
  • 테스트 코드에서 stub 생성이 필요할 땐 의존관계의 객체가 추상체일 경우임
  • 테스트 클래스에서 해당 인터페이스를 가짜로 구현해준다.

Mock

  • 행위 검증에 사용되며 Mockito 모듈을 사용한다.
  • mock(클래스.class) : 해당 클래스의 mock 객체를 생성
  • when().thenReturn() : mock 객체 메소드의 리턴값을 임시로 정의한다.
  • inOrder(mock객체, ...) : 해당 mock 객체의 메소드를 순서대로 테스트할 수 있게 묶어줌
  • verify(mock객체).메소드 : When의 행위에서 해당 mock의 메소드들이 실행되었는지 검사함


IntelliJ 통합 테스트

테스트 클래스 정의

@SpringJUnitConfig
@ActiveProfiles("")
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
class 클래스명{
  ...
}
  • ⬆ 모듈(Bean)간 연결성을 테스트하는 것이므로 IoC 컨테이너를 테스트하기 위한 클래스
  • @SpringJUnitConfig : 테스트용 AppContext를 생성할 수 있게 해줌
  • @ActiveProfiles : 프로필 필터링하기
  • @TestInstance : 클래스 내부에서 static 메소드를 사용하기 위해 객체 하나만 만들어지도록 함
@Autowired
ApplicationContext context;
  • @Autowired를 통해 AppContext와 Bean 객체 생성를 생성할 수 있다.
  • 이렇게 설정해주고 나면 테스트 코드에서 컨테이너 객체들을 가져다 쓰면 됨


테스트용 App Context 정의

@Configuration
static class Config {
  @Bean
  [bean 정의 ...]
}
  • ⬆ Bean 정의용 static 클래스를 만들어주거나
@Configuration
@ComponentScan
static class Config {
}
  • ⬆ 그냥 컴포넌트 스캔해도 된다. (이렇게 쓰자)