본문 바로가기

TDD이론과연습&리팩토링

자바 플레이그라운드 문자열 덧셈 계산기

728x90
반응형

목차

    기능 요구사항

    • 쉼표(,) 또는 콜론(:)을 구분자로 가지는 문자열을 전달하는 경우 구분자를 기준으로 분리한 각 숫자의 합을 반환 (예: “” => 0, "1,2" => 3, "1,2,3" => 6, “1,2:3” => 6)
    • 앞의 기본 구분자(쉼표, 콜론)외에 커스텀 구분자를 지정할 수 있다. 커스텀 구분자는 문자열 앞부분의 “//”와 “\n” 사이에 위치하는 문자를 커스텀 구분자로 사용한다. 예를 들어 “//;\n1;2;3”과 같이 값을 입력할 경우 커스텀 구분자는 세미콜론(;)이며, 결과 값은 6이 반환되어야 한다.
    • 문자열 계산기에 숫자 이외의 값 또는 음수를 전달하는 경우 RuntimeException 예외를 throw한다.

    프로그래밍 요구사항

    • indent(들여쓰기) depth를 2단계에서 1단계로 줄여라.
      • depth의 경우 if문을 사용하는 경우 1단계의 depth가 증가한다. if문 안에 while문을 사용한다면 depth가 2단계가 된다.
    • 메소드의 크기가 최대 10라인을 넘지 않도록 구현한다.
      • method가 한 가지 일만 하도록 최대한 작게 만들어라.
    • else를 사용하지 마라.

    1. 빈 문자열 또는 null 값을 입력할 경우 0을 반환해야 한다.(예 : “” => 0, null => 0)

    if (text == null) {}
    if (text.isEmpty()) {}
    

    2. 숫자 하나를 문자열로 입력할 경우 해당 숫자를 반환한다.(예 : “1”)

    int number = Integer.parseInt(text);
    

    3. 숫자 두개를 컴마(,) 구분자로 입력할 경우 두 숫자의 합을 반환한다.(예 : “1,2”)

    String[] numbers = text.split(",");
    // 앞 단계의 구분자가 없는 경우도 split()을 활용해 구현할 수 있는지 검토해 본다.
    

    4. 구분자를 컴마(,) 이외에 콜론(:)을 사용할 수 있다. (예 : “1,2:3” => 6)

    String[] tokens= text.split(",|:");
    

    5. “//”와 “\n” 문자 사이에 커스텀 구분자를 지정할 수 있다. (예 : “//;\n1;2;3” => 6)

    // java.util.regex 패키지의 Matcher, Pattern import
    Matcher m = Pattern.compile("//(.)\n(.*)").matcher(text);
    if (m.find()) {
        String customDelimiter = m.group(1);
        String[] tokens= m.group(2).split(customDelimiter);
        // 덧셈 구현
    }
    

    6. 음수를 전달할 경우 RuntimeException 예외가 발생해야 한다. (예 : “-1,2,3”)

    • 구글에서 “junit4 expected exception”으로 검색해 해결책을 찾는다.

    TestCase 소스 코드

    import org.junit.jupiter.api.Test;
    
    import static org.assertj.core.api.Assertions.assertThat;
    import static org.assertj.core.api.Assertions.assertThatThrownBy;
    
    public class StringAddCalculatorTest {
        @Test
        public void splitAndSum_null_또는_빈문자() {
            int result = StringAddCalculator.splitAndSum(null);
            assertThat(result).isEqualTo(0);
    
            result = StringAddCalculator.splitAndSum("");
            assertThat(result).isEqualTo(0);
        }
    
         @Test
        public void splitAndSum_숫자하나() throws Exception {
            int result = StringAddCalculator.splitAndSum("1");
            assertThat(result).isEqualTo(1);
        }
    
        @Test
        public void splitAndSum_쉼표구분자() throws Exception {
            int result = StringAddCalculator.splitAndSum("1,2");
            assertThat(result).isEqualTo(3);
        }
    
        @Test
        public void splitAndSum_쉼표_또는_콜론_구분자() throws Exception {
            int result = StringAddCalculator.splitAndSum("1,2:3");
            assertThat(result).isEqualTo(6);
        }
    
        @Test
        public void splitAndSum_custom_구분자() throws Exception {
            int result = StringAddCalculator.splitAndSum("//;\n1;2;3");
            assertThat(result).isEqualTo(6);
        }
    
        @Test
        public void splitAndSum_negative() throws Exception {
            assertThatThrownBy(() -> StringAddCalculator.splitAndSum("-1,2,3"))
                    .isInstanceOf(RuntimeException.class);
        }
    }

     

     


    요구사항 기반으로 기능 목록 정의

    • 문자열을 더해주는 메인 메소드 구현
    • 문자열을 int형으로 바꿔주는 기능 구현
      • int로 변환시 숫자가 아니거나 음수의 경우 RuntimeException 발생
    • 문자열을 쪼개는 splitText 메소드 구현 
      • 문자열이 null이거나 비어있으면 0을 리턴
      • custom 키워드가 포함되어있는지 체크한다.
        • custom키워드를 찾는다. 
        • custom키워드를 제외한 텍스트를 다시 정의한다. 
      • 문자열을 seperator를 기반으로 쪼갠다.

    구현코드

    public class StringAddCalculator {
    
      private static String CUSTOM_PATTERN = "//(.)\n(.*)";
    
      // 문자열 더하는 메인 메소드 
      public int calculator(String text) {
        int result = 0;
        for(String txt : splitText(text)) {
          result += parseNumber(txt);
        }
        return result;
      }
    
      // 문자열을 쪼개는 메소드 
      public String[] splitText(String text) {
        String seperator = ",|:";
        if(null == text || text.isEmpty()) return new String[]{"0"};
    
        if(usedCustomSeparator(text)) {
          seperator = findSeparator(text);
          text = text.substring(4);
        }
    
        return text.split(seperator);
      }
    
      // 커스텀키워드 찾는 메소드 
      private String findSeparator(String text) {
        Matcher m = Pattern.compile(CUSTOM_PATTERN).matcher(text);
        if(m.find()) return m.group(1);
        return null;
      }
    
      // 커스텀키워드가 존재하는지 체크 
      public boolean usedCustomSeparator(String text) {
        return text.matches(CUSTOM_PATTERN);
      }
    
      // 숫자로 변환하는 메소드
      public int parseNumber(String text) {
        int num;
        try {
          num = Integer.parseInt(text);
          if(num < 0) throw new RuntimeException();
        } catch (NumberFormatException e) {
          throw new RuntimeException();
        }
        return num;
      }
    }
    728x90
    반응형