가끔 메소드에서 로직을 처리하다가, 매개변수등의 문제로 로직을 처리할 수 없는 상황임을 명시적으로 호출한 곳에 알려야 할 때가 있다.
그럴때는 throw new 키워드를 통해 Exception 객체를 생성하여 호출한 곳으로 던질 수 있다.
특히 Java에서 예외상황으로 판단하는 경우가 아니더라도 로직적으로 문제가 있는 상황이면 직접 Exception 클래스를 상속받아, 적절한 예외타입을 생성 후, 해당 예외를 던져주는 것이 좋다.
아래는 TDD의 주요 단계이다.
몇가지 신경 써야 할 것은, 처음부터 완벽한 코드를 작성하려 하지 않고 테스트를 통과시키기 위한 최소한의 코드를 작성하고 수정하는 것을 반복해야 한다는 것이다.
TDD의 단계
테스트 작성 (Test):
개발자는 실제 코드를 작성하기 전에 해당 기능 또는 모듈에 대한 테스트 케이스를 작성한다.
테스트 케이스는 예상되는 기능의 동작을 정의하고, 그 동작을 확인하기 위한 기대 결과를 포함한다.
테스트 실행 (Run):
작성한 테스트 케이스를 실행하여 현재 코드의 상태에서 테스트가 실패함을 확인한다.
처음에는 당연히 실패하게 된다.
코드 작성 (Code):
테스트를 통과시키기 위한 최소한의 코드를 작성합한다.
여기서 중요한 점은 테스트가 성공하도록 코드를 작성하는 것이 목표이다.
테스트 실행 및 리팩터링 (Refactor):
작성한 코드를 다시 테스트한다.
테스트가 통과하면 코드를 리팩터링하여 코드의 가독성과 유지보수성을 향상시킵니다.
반복 (Repeat):
위의 단계들을 반복하면서 점진적으로 소프트웨어를 개발한다.
새로운 기능을 추가하거나 기존의 기능을 수정할 때마다 테스트를 통과하는 코드를 작성하는 방식으로 진행된다.
아래 코드는 선생님이 말한 다항식을 입력받았을 때 처리 할 수 있는 메소드를 구현해본 코드이다.
package com.ll;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class Calc {
public static int run(String exp) {
List bits = new ArrayList(Arrays.stream(exp.split(" ")).toList());
while (bits.contains("(")) {
List leftParenthesis = new ArrayList();
List rightParenthesis = new ArrayList();
System.out.println("firstBits = " + bits.toString());
for (int i = 0; i < bits.size(); i++) {
if (bits.get(i).equals("(")) {
leftParenthesis.add(i);
} else if (bits.get(i).equals(")")) {
rightParenthesis.add(i);
}
}
System.out.println("leftParenthesis = " + leftParenthesis);
System.out.println("rightParenthesis = " + rightParenthesis);
int endIndex = rightParenthesis.get(0);
int startIndex = 0;
for (int i = leftParenthesis.size() - 1; i >= 0; i--) {
if (leftParenthesis.get(i) < endIndex) {
startIndex = leftParenthesis.get(i);
break;
}
}
int result = calcBits(new ArrayList<>(bits.subList(startIndex + 1, endIndex)));
bits.set(startIndex, "" + result);
for (int i = startIndex + 1; i <= endIndex; i++) {
bits.remove(startIndex + 1);
}
}
return calcBits(bits);
}
private static int calcBits(List bits) {
System.out.println(bits);
int indexOfMultiOrDev = Integer.MAX_VALUE;
while (bits.contains("*") || bits.contains("/")) {
if (bits.contains("*")) {
indexOfMultiOrDev = Math.min(indexOfMultiOrDev, bits.indexOf("*"));
}
if (bits.contains("/")) {
indexOfMultiOrDev = Math.min(indexOfMultiOrDev, bits.indexOf("/"));
}
if (indexOfMultiOrDev > -1) {
int pre = Integer.parseInt(bits.get(indexOfMultiOrDev - 1));
int post = Integer.parseInt(bits.get(indexOfMultiOrDev + 1));
if (bits.get(indexOfMultiOrDev).equals("*")) {
bits.set(indexOfMultiOrDev - 1, "" + pre * post);
} else {
bits.set(indexOfMultiOrDev - 1, "" + pre / post);
}
bits.remove(indexOfMultiOrDev);
bits.remove(indexOfMultiOrDev);
indexOfMultiOrDev = Integer.MAX_VALUE;
}
}
String oper = null;
int curretnInt = 0;
for (String bit : bits) {
if (isInt(bit)) {
if (oper == null) {
curretnInt = Integer.parseInt(bit);
} else {
if (oper.equals("+")) {
curretnInt += Integer.parseInt(bit);
oper = null;
} else if (oper.equals("-")) {
curretnInt -= Integer.parseInt(bit);
oper = null;
}
}
} else {
oper = bit;
}
}
return curretnInt;
}
public static boolean isInt(String input) {
try {
Integer.parseInt(input);
return true;
} catch (NumberFormatException e) {
}
return false;
}
}
반성점
TTD에 대한 정확한 인식이 없어서, 단계적인 테스트와 개선으로 코드를 짜 나간게 아니라, 최종적인 결과물만을 생각하며 작성하였다.
점진적인 테스트 작성과 리펙토링을 반복하는 개발방식을 도입하고,
여러가지 예외사항에 대한 준비도 필요했다고 생각한다.