본문 바로가기
Spring&SpringBoot/<토비의 스프링 3.1 Vol1.1>, 이일민

테스트 도구 JUnit와 객체지향을 위한 테스트 주도 설계 기법

by 민휘 2023. 3. 8.

JUnit 소개

JUnit은 사실상 자바의 표준 테스팅 프레임워크다.

스프링 테스트 모듈이 JUnit을 이용하며, 스프링 프레임워크 자체도 JUnit을 사용해 만들어졌다.

 

애플리케이션 규모가 커지면 테스트가 많아지고, 테스트 수행 부담이 커진다.

JUnit은 테스트 결과를 종합해서 보고 실패한 곳을 빠르게 확인하는 뷰를 제공한다.

또 일관적인 실행 결과를 위해 패턴을 지원하고, 많은 테스트를 간단히 실행시킬 수 있다.

 

 

JUnit의 테스트 메소드 실행 방법

JUnit은 테스트 메소드가 실행될 때마다 새로운 테스트 인스턴스를 생성한다.

그 이유는 테스트가 독립적으로 실행됨을 보장하기 위함이다.

JUnit이 하나의 테스트 클래스를 가져와 테스트를 수행하는 방법은 다음과 같다.

  1. 테스트 클래스에서 @Test가 붙은 public이고 void형이며 파라미터가 없는 테스트 메소드를 모두 찾는다.
  2. 테스트 클래스의 오브젝트를 하나 만든다.
  3. @Before가 붙은 메소드가 있으면 실행한다.
  4. @Test가 붙은 메소드를 하나 호출하고 테스트 결과를 저장한다.
  5. @After가 붙은 메소드가 있으면 실행한다.
  6. 나머지 테스트 메소드에 대해 2~5번을 반복한다.
  7. 모든 테스트의 결과를 종합해 보여준다.

 

 

테스트 코드의 리팩터링

테스트 코드도 리팩토링할 수 있다.

테스트 코드가 이미 자신에 대한 테스트이기 때문에 테스트 결과가 일정하게 유지된다면 얼마든지 리팩터링할 수 있다.

내부구조와 설계를 개선해서 더 깔끔하고 이해하기 쉬우며 변경이 용이한 코드로 만들 필요성이 있다.

 

 

보통 하나의 테스트 클래스 안에 있는 테스트 메소드들은 공통적인 준비 작업과 정리 작업이 필요한 경우가 많다.

이런 작업을 JUnit이 제공하는 @BeforeAll나 @BeforeEach 메소드로 빼면 JUnit이 테스트 메소드 실행 전에 실행시켜준다.

만약 테스트 메소드 일부에서만 사용되는 코드가 있다면 일반적인 메소드 추출을 사용하는 것이 좋다.

 

 

특히 테스트를 수행하는데 필요한 정보나 오브젝트를 픽스처라고 하는데, 픽스처는 테스트 메소드에서 중복되는 경우가 많다.

그래서 인스턴스 필드로 두고 @Before 메소드에서 생성해 사용한다.

 

 

Junit5은 @BeforeEach과 @BeforeAll를 제공하는데, 어떤 차이가 있을까?

각각 JUnit4의 @Before과 @BeforeClass에 추가 기능이 붙은 애노테이션들인데, 본질만 짚어보자.

@Before는 모든 테스트 메소드 실행 전에 수행되는 메소드이고, @BeforeClass는 테스트 클래스에 속한 테스트 메소드들이 실행되기 전 딱 한번 실행된다. 데이터베이스 접근과 같이 비용이 큰 설정을 해야할 때 적합하다.

 

 

TDD

TDD는 테스트 코드를 먼저 만들고, 테스트를 성공하게 해주는 코드를 작성하는 방식의 개발 방법이다. 이때 테스트 코드는 잘 작성된 기능정의서이다.

 

테스트를 먼저 만들고 그 테스트가 성공하도록 하는 코드만 만드는 방식으로 진행하기 때문에 테스트 코드를 작성하는 장점이 극대화된다. 테스트를 꼼꼼하게 만들 수 있고, 매우 빠른 피드백을 받을 수 있다. 테스트가 성공하는 것을 보며 작성한 코드에 대한 확신을 얻을 수 있다. 개발과 테스트의 간격이 짧기 때문에 오류를 찾기 쉽다. 테스트는 독립적이고 애플리케이션 코드보다 짧기 때문에 전체적인 개발 속도가 빨라진다.

 

객체지향적인 설계를 위해 TDD를 사용할 수 있다. 테스트 코드는 객체가 메시지를 수신할 때 어떤 결과를 반환하고 그 과정에서 어떤 객체와 협력할 것인지에 대한 기대를 코드의 형태로 작성한다. 테스트 주도 개발이 응집도가 높고 결합도가 낮은 클래스로 구성된 시스템을 개발할 수 있게 하는 최상의 프랙티스이다.

 

하지만 객체 지향에 대한 경험이 적은 초보자들은 어떤 테스트를 어떤 식으로 작성해야 하는지 결정하는데 큰 어려움을 느낀다. 테스트 주도 개발은 객체지향에 대한 깊이 있는 지식을 요구한다. 테스트를 작성하기 위해 객체의 메서드롤 호출하고 반환값을 검증하는 것은 순간적으로 객체가 수행해야 하는 책임에 관해 생각한 것이다. 역할, 책임, 협력에 집중하고 객체지향의 원칙을 적용하려는 깊이 있는 고민과 노력을 통해서만 테스트 주도 개발의 혜택을 누릴 수 있다.