→ 말 그대로 테스트 주도적으로 프로그램을 개발 하는 방법.
전통적으로는 프로그램 개발이 완료된 후에 그 프로그램이 제대로 작동하는지, 테스트를 작성한다. 하지만 테스트 주도개발(TDD)는 프로그램을 개발할 때, 테스트 코드를 먼저 작성하고 그 테스트 코드를 통과하는 실제코드를 나중에 만든다.
예시)
우리가 집을 짓는다고 가정해보자.
집을 짓기 위해 벽돌을 어디에 얼마나 쌓을 건지 특정 영역에 실로 표시를 해두고, 벽돌을 쌓다가 표시해 둔 실 까지 벽돌이 채워지면, 벽돌을 쌓는 것을 중지한다.
TDD를 여기에 비유한다면, 실로 영역을 지정 하는 것을 '테스트 코드', 실제로 벽돌을 쌓는 과정을 '실제 코드'에 비유할 수 있다. 벽돌을 쌓을 때, 벽돌이 튀어나오거나, 모양이 안맞는 것을 실이 '판단'을 해준다.
→ 즉, '실'이라는 테스트 코드가 '벽돌 쌓기'라는 실제 코드가 나아갈 방향을 제시를 해준다.
만약 벽돌을 쌓던 중, 벽돌이 조금 비뚤어졌다면, 다시 반듯하게 잡아야하는데, 이것을 리팩토링에 비유할 수 있다.
💡 리팩토링은 소스코드의 기능은 유지한 채로 소스코드의 디자인을 개선해 나가는 방법이다.
TDD의 일반적인 흐름은 다음과 같다.
여기서 N은 " 가장 간단한 코드가 만들어 질 때까지" 이다.
→ 프로그램을 시작하고, 구현한 프로그램을 테스트하는 용도로 사용
빠른 기간내에 소프트웨어를 작성해야 한다면 실제코드 만 작성 하는것이 효율적이지만,
소프트웨어의 품질, 완성도를 높히기 위해서는 TDD방식이 효율적이다.
테스트 코드를 쉽게 사용할 수 있는 자바 라이브러리
다양한 assertion을 제공해주는 자바 라이브러리.
→ 테스트 코드의 가독성을 매우 높혀준다. ( Junit이 기본 제공해 주는 메소드보다 가독성이 매우 높다)
자바는 컴파일 언어이다.
.java 파일을 실행시키는게아니라, .java의 컴파일 결과인 .class을 실행시키는 것이다.
처음 프로젝트 구조를 설헝 할 때는, IntelliJ와 같은 IDE에서는 .class 파일이 담긴 경로를 알아야한다. 이것을 classPath 설정이라고한다
gradle을 사용할 때는 classpath가 잘 설정이 되어 있는지 확인해야한다.
→테스트 코드를 실행하기위해 .class의 위치를 알아두기 위함.
우선 프로젝트에 코끼리 모양의 build.gradle 모양 폴터를 누르고,plugin에 'java'가 포함되어 있는지 확인 해야한다.
gradle은 기본 셋팅으로 build 폴더 내부에 컴파일된 소스 구조를 만든다.
우선 그래들을 이용하여 assertJ를 넣어준다.
→ Java 8 버전 이상이면 assertJ 를 3.0 버전 이상으로 셋팅해야한다. 이전 버전은 2.X 버전으로 설정
project/src/test폴더에서 초록색 java폴더를 클릭해주면, 테스트 폴더를 설정 해줄 수 있다.
다음과 같이 java 폴더를 test 폴더로 설정 해주면 된다.
java/Calculator.java 생성 후 코드 작성
public class Calculator {
int num1;
int num2;
public Calculator(int num1, int num2) {
this.num1 = num1;
this.num2 = num2;
}
public int add(int num1, int num2){
return num1 + num2;
}
}
소스코드를 작성 하고, command + shift + t 단축어를 누르면 Create Test를 할 수가 있다.
그후에 원하는 버전의 JUnit을 설정하고 test 파일을 만들어 주면 된다.
그렇다면 이렇게 test 폴더안에 CalculatorTest 파일이 생성 된 것을 알 수 있다.
우리는 현재 java/Calculator 에는 생성자 밖에 있지 않다. 즉 계산기의 실질적인 기능들 중 하나인 add, sub, mul 등이 없다.
그중 add 메소드를 TDD 방식으로 만들어 보겠다. 즉 테스트 파일을 먼저 만들고 실제 코드를 작성 해보겠다.
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.*;
class CalculatorTest {
@Test
@DisplayName("add 함수를 위한 테스트 코드 입니다.")
void add() {
Calculator calculator = new Calculator(1,2);
assertThat(calculator.add(1,2)).isEqualTo(3);
}
}
파일을 작성해보고, 테스트를 해보면 정상으로 실행 되는지 확인이 가능하다.
실행 화면 1 .
1 + 2가 3인지 테스트
public class Calculator {
int num1;
int num2;
public Calculator(int num1, int num2) {
this.num1 = num1;
this.num2 = num2;
}
public int add(int num1, int num2){
return num1 + num2;
}
public int sub(int num1,int num2){
return num1 - num2;
}
public int div(int num1, int num2) {
return num1/num2;
}
public int mul(int num1, int num2) {
return num1*num2;
}
}
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.*;
class CalculatorTest {
Calculator calculator = new Calculator(1,2);
@BeforeEach
void setUp() {
calculator = new Calculator(1, 2);
}
@Test
@DisplayName("add 함수를 위한 테스트 코드 입니다.")
void add() {
assertThat(calculator.add(1,2)).isEqualTo(3);
}
@Test
@DisplayName("sub 함수를 위한 테스트 코드 입니다.")
void sub() {
assertThat(calculator.sub(10,5)).isEqualTo(5);
}
@Test
@DisplayName(" div 함수를 위한 테스트 코드 입니다.")
void div() {
assertThat(calculator.div(6,2)).isEqualTo(3);
}
@Test
@DisplayName("mul 함수를 위한 테스트 코드 입니다.")
void mul() {
assertThat(calculator.mul(2,5)).isEqualTo(10);
}
}