이 사이트의 실습은 자바스크립트를 켜야 움직입니다. 아래는 같은 내용을 글로 적은 것입니다.
기초개념 › Spring
테스트 코드는 무엇이고, 통과와 실패는 누가 정하는가
테스트 코드는 "이 메서드에 이것을 넣으면 이것이 나와야 한다"를 코드로 적어 둔 것입니다. 이 실습의 CalcTest 클래스가 그 예입니다. 그 안의 adds() 메서드가 Calc 클래스의 add(2, 3)을 부르고, assertEquals(5, ...)가 add가 돌려준 값을 기대한 값 5와 견줍니다. 두 값이 다르면 그 줄에서 오류가 납니다. adds() 위의 @Test는 "이 메서드가 테스트"라는 표시입니다. 이 코드를 실행하는 것은 우리가 아니라 테스트 도구 JUnit입니다. JUnit이 @Test가 붙은 메서드를 찾아 부르고, 오류 없이 끝나면 통과, assertEquals가 낸 오류로 끝나면 실패로 셉니다. 이 실습은 add를 틀리게 고치거나, 기대한 값을 틀리게 적거나, @Test를 지워 가며 같은 코드를 실제 JUnit으로 실행해, 찾은 테스트 수와 통과와 실패 판정, 실패 메시지가 어떻게 달라지는지 봅니다. (화면의 코드는 import 줄을 줄였습니다.)
실행으로 대조 · JDK 21과 JUnit 6.0.3에서 여덟 가지 조합을 컴파일하고 JUnit Launcher로 실행해 찾은 테스트 수, 통과와 실패, 실패 메시지를 대조
// 검사받는 코드
class Calc {
int add(int a, int b) {
return a + b;
}
}
// 테스트 코드: Calc가 맞게 동작하는지 확인하는 코드
class CalcTest {
// 표시: JUnit은 @Test가 붙은 메서드를 찾아 테스트로 실행한다
@Test
void adds() {
// 판정: 앞의 값(기대한 값)과 뒤의 값(실제 값)이 다르면 실패
assertEquals(5, new Calc().add(2, 3));
}
}
실행한 것은 JDK 21.0.12.1(javac 21)과 JUnit Jupiter 6.0.3, JUnit Platform Launcher 6.0.3입니다. 여덟 가지 조합을 모두, 화면의 코드 맨 위에 import 두 줄(org.junit.jupiter.api.Test, Assertions.assertEquals)만 더한 같은 소스를 javax.tools로 컴파일하고, JUnit Platform Launcher를 코드로 불러 CalcTest 클래스를 실행해 요약을 얻은 결과와 대조했습니다. 터미널에서 ConsoleLauncher를 쓴 것이 아니라 같은 도구의 Launcher API를 직접 썼습니다. 대조한 것은 찾은 테스트 수, 시작한 수, 성공과 실패의 수, 실패한 예외의 종류(org.opentest4j.AssertionFailedError)와 메시지의 첫 줄입니다. 메시지 글자 expected: <5> but was: <-1>은 이 JUnit이 실제로 낸 글 그대로입니다. 단계 문장이 기대는 사실로, 호출 횟수를 세는 필드를 더한 별도의 소스를 같은 방식으로 실행해, @Test가 있으면 우리 코드가 부르는 줄 없이 adds()와 add가 한 번씩 실행되고 @Test를 지우면 둘 다 0번인 것을 확인했습니다. 문서는 JUnit User Guide(docs.junit.org, 6.1.3판)의 Definitions 절에서 테스트 메서드가 @Test 등이 붙은 인스턴스 메서드이고 테스트 클래스는 테스트 메서드를 가진 클래스라는 것, Test Classes and Methods 절에서 테스트 클래스와 메서드가 public일 필요는 없지만 private이면 안 되고 값을 돌려주면 안 된다는 것, Assertions 절에서 JUnit Jupiter의 단언이 org.junit.jupiter.api.Assertions의 static 메서드이고 예제가 assertEquals(2, calculator.add(1, 1))처럼 기대한 값을 앞에 적는다는 것을, API 문서에서 @Test가 메서드가 테스트 메서드임을 알리는 표시이고 private이거나 static이면 안 된다는 것, Assertions의 설명(실패한 단언은 따로 정한 것이 없으면 AssertionFailedError나 그 하위 타입을 던진다)과 assertEquals(int expected, int actual)의 요약(expected와 actual이 같다고 단언한다)을 열어 확인했습니다. 문서는 6.1.3판이고 실행한 JUnit은 6.0.3판입니다. 문서가 정한 것과 이 실행에서 관찰한 것은 다릅니다. 오류 없이 끝나면 통과이고 오류로 끝나면 실패로 세는 것, @Test가 없는 메서드를 찾지 않아 찾은 테스트가 0개이고 실패도 0개로 세는 것은 이 JUnit에서 관찰한 동작입니다(ConsoleLauncher의 종료 코드나 빌드 도구가 테스트 0개를 어떻게 다루는지는 실행하지 않았습니다). assertEquals의 앞뒤 값 중 앞이 기대한 값이라는 것은 메서드 이름과 인자 이름(expected, actual)으로 확인했고, 문서가 순서를 규칙으로 따로 적어 두지는 않았습니다. 화면은 테스트 한 개만 다루고, 테스트 이름 붙이기, 여러 개의 단언, 준비와 정리 메서드, 스프링 컨텍스트를 띄우는 테스트, @MockitoBean 같은 가짜 객체, 테스트를 자동으로 돌리는 빌드 과정은 다루지 않습니다. 스프링 컨텍스트를 띄우는 테스트는 "세부 동작 실습: 테스트", 테스트를 올릴 때마다 자동으로 돌리는 것은 "세부 동작 실습: CI/CD 파이프라인"에서 다룹니다.
줄을 그은 곳은 처음 코드에서 지운 것이고, 색을 칠한 곳은 새로 쓴 것입니다.