728x90
단위 테스트 실습 - 문자열 계산기
다음 요구사항을 JUnit을 활용해 단위 테스트 코드를 추가해 구현한다.
요구사항
- 사용자가 입력한 문자열 값에 따라 사칙연산을 수행할 수 있는 계산기를 구현해야 한다.
- 문자열 계산기는 사칙연산의 계산 우선순위가 아닌 입력 값에 따라 계산 순서가 결정된다. 즉, 수학에서는 곱셈, 나눗셈이 덧셈, 뺄셈 보다 먼저 계산해야 하지만 이를 무시한다.
- 예를 들어 "2 + 3 * 4 / 2"와 같은 문자열을 입력할 경우 2 + 3 * 4 / 2 실행 결과인 10을 출력해야 한다.
본격적으로 TDD 연습에 들어가기전에
기존 소스를 단위 테스트로 변경하면서 리팩토링 연습을 해보고 싶어서 막코딩(?)을 먼저 했다
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
public class StringCalculator {
/* 사용자가 입력한 문자열 값에 따라 사칙연산을 수행할 수 있는 계산기를 구현해야 한다.
문자열 계산기는 사칙연산의 계산 우선순위가 아닌 입력 값에 따라 계산 순서가 결정된다. 즉, 수학에서는 곱셈, 나눗셈이 덧셈, 뺄셈 보다 먼저 계산해야 하지만 이를 무시한다.
예를 들어 "2 + 3 * 4 / 2"와 같은 문자열을 입력할 경우 2 + 3 * 4 / 2 실행 결과인 10을 출력해야 한다. */
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
String value = scanner.nextLine();
String[] values = value.split(" ");
List<Integer> intList = new ArrayList<>();
List<String> signList = new ArrayList<>();
for(int i=0; i<values.length; i++){
if(i%2 == 1){
signList.add(values[i]);
}else if(i%2 == 0){
intList.add(Integer.parseInt(values[i]));
}
}
int result = intList.get(0);
int index = 0;
for(String sign:signList){
index++;
switch (sign){
case "+":
result = result + intList.get(index);
break;
case "-":
result = result - intList.get(index);
break;
case "*":
result = result * intList.get(index);
break;
case "/":
result = result / intList.get(index);
break;
}
}
System.out.println("result: " + result);
}
}
함수를 기능별로 단위화 하지도 않았고, 우선 요구사항에 맞춰 동작하도록 코드를 짰다
그리고 하나하나 기능별로 함수를 선언하는 방식으로 리팩토링하며 단위 테스트를 진행했다
1. 문자열을 배열로 변경
public String[] stringToStringArray(String str){
return str.split(" ");
}
2. 문자를 숫자 형태로 타입 변경
public int stringToInt(String str){
return Integer.parseInt(str);
}
3. 입력받은 문자들을 숫자와 부호로 구분
public Map<String, Object> intAndSignSeparation(String[] values){
Map<String, Object> resultMap = new HashMap<>();
List<Integer> intList = new ArrayList<>();
List<String> signList = new ArrayList<>();
for(int i=0; i<values.length; i++){
if(i%2 == 1){
signList.add(values[i]);
}else if(i%2 == 0){
intList.add(stringToInt(values[i]));
}
}
resultMap.put("intList", intList);
resultMap.put("signList", signList);
return resultMap;
}
4. +, -, *, / 사칙연산
public int plusCalculation(int a, int b){
return a + b;
}
public int minusCalculation(int a, int b){
return a - b;
}
public int multiplicationCalculation(int a, int b){
return a * b;
}
public int divisionCalculation(int a, int b){
return a / b;
}
5. 계산 인수를 받아 처리하는 함수 (실패시 0을 리턴하도록)
public int calculator(int a, String sign, int b){
int result = 0;
try{
switch (sign){
case "+":
result = plusCalculation(a,b);
break;
case "-":
result = minusCalculation(a,b);
break;
case "*":
result = multiplicationCalculation(a,b);
break;
case "/":
result = divisionCalculation(a,b);
break;
}
}catch (Exception e){
return 0;
}
return result;
}
6. main
public static void main(String[] args) {
StringCalculator stringCalculator = new StringCalculator();
Scanner scanner = new Scanner(System.in);
String value = scanner.nextLine();
String[] values = stringCalculator.stringToStringArray(value);
Map<String, Object> valuesSeparationMap = stringCalculator.intAndSignSeparation(values);
List<Integer> intList = (List<Integer>) valuesSeparationMap.get("intList");
List<String> signList = (List<String>) valuesSeparationMap.get("signList");
int result = intList.get(0);
int index = 0;
for(String sign:signList){
index++;
stringCalculator.calculator(result, sign, intList.get(index));
}
System.out.println("result: " + result);
}
7. 최종 단위 테스트 결과
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import java.util.*;
import static org.assertj.core.api.Assertions.assertThat;
class StringCalculatorTest {
StringCalculator stringCalculator;
@BeforeEach
public void SetUp(){
stringCalculator = new StringCalculator();
}
@DisplayName("문자열 스페이스바(' ') 기준으로 나누기")
@Test
void stringToStringArray() {
String str = "2 + 10 / 2";
String[] strArray = {"2", "+", "10", "/", "2"};
assertThat(strArray).isEqualTo(stringCalculator.stringToStringArray(str));
}
@DisplayName("문자를 숫자로 타입 변경")
@Test
void stringToInt() {
assertThat(3).isEqualTo(stringCalculator.stringToInt("3"));
}
@DisplayName("숫자, 부호 타입별로 구분")
@Test
void intAndSignSeparation() {
Map<String, Object> resultMap = new HashMap<>();
List<Integer> intList = new ArrayList<>(Arrays.asList(2,10,2));
List<String> signList = new ArrayList<>(Arrays.asList("+","/"));
resultMap.put("intList", intList);
resultMap.put("signList", signList);
String[] strArray = {"2", "+", "10", "/", "2"};
assertThat(resultMap).isEqualTo(stringCalculator.intAndSignSeparation(strArray));
}
@DisplayName("더하기 계산")
@Test
void plusCalculation() {
assertThat(6).isEqualTo(stringCalculator.plusCalculation(4,2));
}
@DisplayName("빼기 계산")
@Test
void minusCalculation() {
assertThat(2).isEqualTo(stringCalculator.minusCalculation(4,2));
}
@DisplayName("곱하기 계산")
@Test
void multiplicationCalculation() {
assertThat(8).isEqualTo(stringCalculator.multiplicationCalculation(4,2));
}
@DisplayName("나누기 계산")
@Test
void divisionCalculation() {
assertThat(2).isEqualTo(stringCalculator.divisionCalculation(4,2));
}
@DisplayName("최종 값 계산")
@Test
void calculator() {
assertThat(6).isEqualTo(stringCalculator.calculator(4,"+",2));
}
}
728x90
'개발 교육 > 플레이그라운드 with TDD, 클린코드' 카테고리의 다른 글
TDD/리팩토링 실습 - 문자열 덧셈 계산기 (0) | 2022.03.09 |
---|---|
숫자야구게임 다시 구현 - 피드백 적용 후 (0) | 2022.03.06 |
숫자야구게임 구현 - 피드백 적용 전 (0) | 2022.03.06 |
AssertJ 맛보기(2) (0) | 2022.03.01 |
AssertJ 맛보기(1) (0) | 2022.03.01 |