📖 단위 테스트란?
- 단위 테스트는 작은 논리 또는 코드를 테스트하여 코드의 출력이 특정 데이터의 입력 및 / 또는 특정 조건을 충족할 때 예상한 대로인지 확인합니다. 일반적으로 단위 테스트는 다른 테스트와 독립적이어야 한다.
- 단위 테스트는 메서드 나 클래스 일 수 있는 작은 코드 단위만 대상으로 한다.
- 개발자가 현재 논리의 문제와 현재 변경으로 인한 회귀 실패를 발견하는 데 도움이 되고, 또한 현재 코드가 향후 구현에 어떻게 영향을 미칠 수 있는지에 대한 통찰력을 제공한다.
📗 main method
main method의 용도
- 프로그램을 시작
- 구현한 프로그램을 테스트
여기서는 main method를 테스트 용도로 사용하는 경우를 가정하고 있다.
가장 간단한 사칙연산을 예로 들어 보자
사칙연산이 가능한 계산기
- 덧셈(add)
- 뺄셈(substract)
- 곱셈(muntiply)
- 나눗셈(divide)
위 4개의 기능을 프로덕션 코드(실제 로직이 구현되어 있는 코드)에 구현하고 이를 main method를 활용해 테스트한다.
- 위 그림을 통해 확인할 수 있듯이 프로덕션 코드(Production Code) 프로그램 구현을 담당하는 부분으로 사용자가 실제로 사용하는 소스 코드를 의미한다.
- 테스트 코드(test code)는 프로덕션 코드가 정상적으로 동작하는지를 확인하는 코드이다.
하지만 이러한 main method에는 문제점이 존재한다.
main method 테스트 문제점
- Production code와 Test Code가 클래스 하나에 존재한다. 클래스 크기가 커짐. 복잡도 증가함.
- Test Code가 실 서비스에 같이 배포됨.
- main method 하나에서 여러 개의 기능을 테스트함. 복잡도 증가.
- method 이름을 통해 어떤 부분을 테스트하는지에 대한 의도를 드러내기 힘듦.
- 테스트 결과를 사람이 수동으로 확인
이를 해결하기 위해 등장한 도구가 바로 JUnit이다.
📘 JUnit 이란?
JUnit 은 단위 테스트 도구이다.
자바 애플리케이션에 대한 단위 테스트를 쉽게 해 주는 테스트용 프레임워크라고 이해하면 된다.
외부 테스트 프로그램(케이스)을 작성하여 System.out으로 번거롭게 디버깅하지 않아도 된다는 장점이 있다.
JUnit의 특징
- 단위 테스트 Framework 중 하나
- @Test 메서드가 호출할 때마다 새로운 인스턴스를 생성하여 독립적인 테스트가 이루어지게 한다.
- 문자 혹은 GUI 기반으로 실행됨
- 단정 문으로 테스트 케이스의 수행 결과를 판별함(assertEquals(예상 값, 실제 값))
- 어노테이션으로 간결하게 지원
JUnit의 assert 메서드들
- assertEquals(A, B) : 객체 A와 B가 같은 값을 가지는지 확인한다.
- assertEquals(A, B, C) : 객체 A와 B가 같은 값을 가지는지 확인한다. 여기서 C는 오차범위.
- assertArrayEquals(A, B) : 배열 A와 B가 일치하는지 확인한다.
- assertSame(A, B) : 객체 A와 B가 같은 객체인지 확인한다.
- assertTrue(A) : 조건 A가 참인지 확인한다.
- assertNull(A) : 객체 A가 Null인지 확인한다.
- assertNotNull(A) 객체 A가 Null이 아닌지 확인한다.
JUnit의 어노테이션
- @Test
: 메서드 위에 해당 어노테이션을 선언해, 테스트 대상 메소드임을 지정할 수 있다. - @Test(timeout=밀리초)
: 테스트 메소드 수행 시간을 제한할 수 있다.
테스트메서드가 리턴값을 반환하는 데에 걸리는 시간이 지정된 밀리초를 넘긴다면 해당 테스트는 실패로 판별한다. - @Test(expected=예외)
: 해당 테스트 메소드 예외 발생 여부에 따라 성공/실패를 판별할 수 있다.
expected=에 지정된 예외가 발생해야 테스트가 성공한 것으로 판별한다. - @Ignore
: 해당 어노테이션이 선언된 테스트 메서드를 실행하지 않도록 지정한다. - @BeforeEach == (구)@Before
: 모든 @Test메소드가 실행되기 전에 실행되는 메서드를 지정하는 어노테이션이다.- 각 테스트 시작 전에 각각 호출된다.
- @Test메서드에서 공통으로 사용되는 코드를 @Before메서드에 선언해 사용하면 좋다.
- 테스트마다 공통으로 쓰이면서, 테스트 전에 리셋되어야 할 항목이 들어간다
- @AfterEach == (구)@After
: 모든 @Test메소드의 실행이 끝난 뒤에 실행되는 메서드를 지정하는 어노테이션이다.- 각 테스트가 끝나고 각각 호출된다.
- @BeforeAll == (구)@BeforeClass
: 해당 테스트 클래스가 실행될 때 딱 한 번만 수행되는 테스트 메소드를 지정하는 어노테이션이다. - @AfterAll == (구)@AfterClass
: 해당 테스트 클래스가 실행이 끝난 뒤에 딱 한 번만 수행되는 테스트 메소드를 지정하는 어노테이션이다.
📙 AssertJ 란?
자바 JUnit의 테스트 코드에 사용되면서 테스트 코드를 멋지게(?), 가독성과 편의성을 높여 주는 라이브러리
- 메서드 체이닝을 지원하기 때문에 좀 더 깔끔하고 읽기 쉬운 테스트 코드를 작성할 수 있다.
- 개발자가 테스트를 하면서 필요하다고 상상할 수 있는 거의 모든 메서드를 제공한다.
모든 테스트 코드는 assertThat() 메소드에서 출발한다. 다음과 같은 포맷으로 AssertJ에서 제공하는 다양한 메서드를 연쇄 호출하면서 코드를 작성할 수 있다.
assertThat(테스트타겟).메소드1().메소드2().메소드3();
간단한 문자열 테스트 코드를 통해 AssertJ의 효과를 확인하자
- . isNotEmpty() // 비어있지 않고
- . contains("Hello") // "Nice"를 포함하고
- . contains("world") // "world"도 포함하고
- . doesNotContain("zzz") // "zzz"는 포함하지 않으며
- . startsWith("Hello") // "Hello"로 시작하고
- . endsWith("ld") // "ld"로 끝나며
- . isEqualTo("Hello World"); // Hello World와 같다
- assertThat(테스트 타깃). 메서드 1(). 메서드 2(). 메서드 3()'
이런 포맷으로 AssertJ의 여러 메서드들을 연쇄적으로 호출해 코드를 작성할 수 있다.
(메서드 체이닝)
6개의 메서드를 연쇄적으로 호출하였다. 개인적으로 상당히 직관적이라는 것이 마음에 들었다.
이번엔 간단한 숫자로 테스트해보자
문자열과 마찬가지로 여러 가지 메서드들을 활용할 수 있음을 볼 수 있었다.
- . isPositive() // 양수이고
- . isGreaterThan(3) // 3보다 크며
- . isLessThan(4) // 4보다 작다
- . isEqualTo(3, offset(1d)) // 오프셋 1 기준으로 3과 같고
- . isEqualTo(3.1, offset(0.1d)) // 오프셋 0.1 기준으로 3.1과 같으며
- . isEqualTo(3.14); // 오프셋 없이는 3.14와 같다
AssertJ 사용 시 주의점
- assertThat(Object o)로 테스트할 객체를 호출한 다음 메서드들을 사용해야 한다.
- BAD : assertThat(actual.equals(expected));
GOOD : assertThat(actual).isEqualTo(expected); - BAD : assertThat(1 == 2);
GOOD : assertThat(1).isEqualTo(2);
출처 : 링크 1
감사합니다!
'JAVA with TDD, Clean Code' 카테고리의 다른 글
JAVA(자바) 단위 테스트 실습 - 숫자야구게임 구현 (0) | 2021.09.17 |
---|---|
JAVA(자바) 단위 테스트 실습 - 문자열 계산기 (0) | 2021.09.03 |
간단한 클래스 분리 (0) | 2021.08.21 |
Set Collection에 대한 학습 테스트 (0) | 2021.07.30 |
String 클래스에 대한 학습 테스트 (0) | 2021.07.29 |