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
복사했습니다!