Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[자동차 경주 - 단위테스트] 2단계 - 문자열 덧셈 계산기 #5914

Merged
merged 6 commits into from
Mar 14, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 1 addition & 32 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,35 +6,4 @@
* 모든 피드백을 완료하면 다음 단계를 도전하고 앞의 과정을 반복한다.

## 온라인 코드 리뷰 과정
* [텍스트와 이미지로 살펴보는 온라인 코드 리뷰 과정](https://github.com/next-step/nextstep-docs/tree/master/codereview)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

헛 요구사항은 왜 굳이 삭제하셨나요?? 삭제 안하셔도 됩니다~!

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

제가 임의로 작성한 내용이라서 필요하면 나중에 필요하면 리버트하겠습니다 ㅎ


## 요구사항

### String 클래스에 대한 학습 테스트
#### 요구사항 1
- [ ] "1,2"을 ,로 split 했을 때 1과 2로 잘 분리되는지 확인하는 학습 테스트를 구현한다.
- [ ] "1"을 ,로 split 했을 때 1만을 포함하는 배열이 반환되는지에 대한 학습 테스트를 구현한다.

#### 요구사항 2
- [ ] "(1,2)" 값이 주어졌을 때 String의 substring() 메소드를 활용해 ()을 제거하고 "1,2"를 반환하도록 구현한다.

#### 요구사항 3
- [ ] "abc" 값이 주어졌을 때 String의 charAt() 메소드를 활용해 특정 위치의 문자를 가져오는 학습 테스트를 구현한다.
- [ ] String의 charAt() 메소드를 활용해 특정 위치의 문자를 가져올 때 위치 값을 벗어나면 StringIndexOutOfBoundsException이 발생하는 부분에 대한 학습 테스트를 구현한다.
- [ ] JUnit의 @DisplayName을 활용해 테스트 메소드의 의도를 드러낸다.

### Set Collection에 대한 학습 테스트

#### 요구사항 1
- [ ] Set의 size() 메소드를 활용해 Set의 크기를 확인하는 학습테스트를 구현한다.

#### 요구사항 2
- [ ] Set의 contains() 메소드를 활용해 1, 2, 3의 값이 존재하는지를 확인하는 학습테스트를 구현하려한다.
- [ ] 구현하고 보니 다음과 같이 중복 코드가 계속해서 발생한다.
- [ ] JUnit의 ParameterizedTest를 활용해 중복 코드를 제거해 본다.

#### 요구사항 3
- [ ] 요구사항 2는 contains 메소드 결과 값이 true인 경우만 테스트 가능하다. 입력 값에 따라 결과 값이 다른 경우에 대한 테스트도 가능하도록 구현한다.
- [ ] 예를 들어 1, 2, 3 값은 contains 메소드 실행결과 true, 4, 5 값을 넣으면 false 가 반환되는 테스트를 하나의 Test Case로 구현한다.


* [텍스트와 이미지로 살펴보는 온라인 코드 리뷰 과정](https://github.com/next-step/nextstep-docs/tree/master/codereview)
57 changes: 57 additions & 0 deletions src/main/java/calculator/StringAddCalculator.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package calculator;

import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class StringAddCalculator {

private static final Pattern DEFAULT_DELIMITERS_PATTERN = Pattern.compile("[,:]");
private static final Pattern CUSTOM_DELIMITER_PARSE_PATTERN = Pattern.compile("//(.)\n(.*)");
public static final String VALID_INTEGER_PATTERN = "-?\\d+";

public static int splitAndSum(String text) {

if (text == null || text.isEmpty()) {
return 0;
}

List<String> tokens = splitIntoTokens(text);
return sumPositiveNumbersOrThrow(tokens);
}

private static List<String> splitIntoTokens(String text) {
Matcher matcher = CUSTOM_DELIMITER_PARSE_PATTERN.matcher(text);

if (matcher.find()) {
String customDelimiter = Pattern.quote(matcher.group(1));
return List.of(matcher.group(2).split(customDelimiter));
}

return List.of(DEFAULT_DELIMITERS_PATTERN.split(text));
}

private static int sumPositiveNumbersOrThrow(List<String> tokens) {
int sum = 0;
for (String token : tokens) {
if (!isValidInteger(token)) {
throw new RuntimeException("Invalid input: " + token);
}

int num = Integer.parseInt(token);
if (num < 0) {
throw new RuntimeException("Negative numbers not allowed: " + token);
}

sum += num;
}
return sum;
}

private static boolean isValidInteger(String input) {
if (input == null || input.isEmpty()) {
return false;
}
return input.matches(VALID_INTEGER_PATTERN);
}
}
55 changes: 55 additions & 0 deletions src/test/java/calculator/StringAddCalculatorTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
package calculator;

import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;

import static org.assertj.core.api.AssertionsForClassTypes.assertThat;
import static org.assertj.core.api.AssertionsForClassTypes.assertThatThrownBy;

public class StringAddCalculatorTest {

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

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

displayname 좋습니다. 👍

@Test
public void splitAndSum_null_또는_빈문자() {
int result = StringAddCalculator.splitAndSum(null);
assertThat(result).isEqualTo(0);

result = StringAddCalculator.splitAndSum("");
assertThat(result).isEqualTo(0);
}

@DisplayName("숫자 하나를 문자열로 입력할 경우 해당 숫자를 반환한다.(예 : “1”)")
@Test
public void splitAndSum_숫자하나() throws Exception {
int result = StringAddCalculator.splitAndSum("1");
assertThat(result).isEqualTo(1);
}

@DisplayName("숫자 두개를 컴마(,) 구분자로 입력할 경우 두 숫자의 합을 반환한다.(예 : “1,2”)")
@Test
public void splitAndSum_쉼표구분자() throws Exception {
int result = StringAddCalculator.splitAndSum("1,2");
assertThat(result).isEqualTo(3);
}

@DisplayName("구분자를 컴마(,) 이외에 콜론(:)을 사용할 수 있다. (예 : “1,2:3” => 6)")
@Test
public void splitAndSum_쉼표_또는_콜론_구분자() throws Exception {
int result = StringAddCalculator.splitAndSum("1,2:3");
assertThat(result).isEqualTo(6);
}

@DisplayName("“//”와 “\\n” 문자 사이에 커스텀 구분자를 지정할 수 있다. (예 : “//;\\n1;2;3” => 6)")
@Test
public void splitAndSum_custom_구분자() throws Exception {
int result = StringAddCalculator.splitAndSum("//;\n1;2;3");
assertThat(result).isEqualTo(6);
}

@DisplayName("음수를 전달할 경우 RuntimeException 예외가 발생해야 한다. (예 : “-1,2,3”)")
@Test
public void splitAndSum_negative() throws Exception {
assertThatThrownBy(() -> StringAddCalculator.splitAndSum("-1,2,3"))
.isInstanceOf(RuntimeException.class);
}
}