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

[계산기] 권민관 미션 1차 수정본 입니다! #25

Open
wants to merge 40 commits into
base: mlngwan
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 37 commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
74f7544
docs: 기능 명세서 작성
mlngwan May 7, 2024
903f21d
feat: 기초적인 계산기 초기 단계 구현
mlngwan May 7, 2024
2823002
Docs: TODO 세분화 후 README 수정
mlngwan May 8, 2024
b0c6ed1
Remove: OutputView 삭제
mlngwan May 8, 2024
3bfb2cf
Rename: 파일명 수정
mlngwan May 8, 2024
ed9a151
feat: MVC 구조를 위한 Controller 추가
mlngwan May 8, 2024
a082226
Refactor: Controller 추가로 인한 Caculator 수정
mlngwan May 8, 2024
5352af0
feat: Calculator Test 초안 작성
mlngwan May 8, 2024
2b11bab
feat: Calculator 계산 테스트 구현
mlngwan May 11, 2024
cf79840
feat: 입력내용 저장 테스트 구현
mlngwan May 11, 2024
ec61541
refactor: Test를 위한 CalculatorView 코드 수정
mlngwan May 11, 2024
b8751fc
docs: step3 진행을 위한 문서 작성
mlngwan May 11, 2024
ae57faf
Rename: step3 진행을 위한 문서 이동
mlngwan May 11, 2024
6b1fde1
Feat: StringCalculator 구현
mlngwan May 11, 2024
f7900c1
Feat: StringCalculator DEFAULT 값 추가 및 숫자가 아닌 다른 형식의 경우 오류값 출력 구현
mlngwan May 11, 2024
b1398c6
Test: 테스트명 직관적으로 수정
mlngwan May 11, 2024
31642a6
Test: 문자열 계산기 Test 구현
mlngwan May 11, 2024
63e45f6
Test: 문자열 계산기 Test 쓸모없는 Import 삭제
mlngwan May 11, 2024
d97a6c6
Test: AssertJ를 활용한 Test 작성
mlngwan May 11, 2024
cfe56c3
Refactor: AssertJ 사용을 위한 dependencies 추가
mlngwan May 13, 2024
eb5a102
Rename: Test Code 위치 변경 및 파일 이름 수정
mlngwan May 13, 2024
fc96402
Docs: step4를 위한 문서 작성
mlngwan May 13, 2024
c175799
Refactor: 코드 컨벤션 - 개행 및 정렬 수정
mlngwan May 13, 2024
cab781b
Refactor: Test Code 네이밍 수정
mlngwan May 13, 2024
127590a
Refactor: 상수값 네이밍 재설정 및 새로운 상수값 설정
mlngwan May 14, 2024
a2f073b
Remove: InputView와 OutputView로 분리로 인한 삭제
mlngwan May 14, 2024
6efad2c
Feat: OutView 구현
mlngwan May 14, 2024
b14e0b1
Refactor: 불필요한 개행 삭제
mlngwan May 14, 2024
b01efb9
feat: view 분리 - InputView 구현
mlngwan May 14, 2024
a333ec8
Refactor: 요구사항 준수, 기존의 view에서 담당하던 로직을 model에서 처리하기, 예외처리 추가
mlngwan May 14, 2024
3e57660
Refactor: View와 Model 리팩토링으로 인해 수정, 기존의 outputView가 담당해야 하는 부분 수정
mlngwan May 14, 2024
76e6def
Refactor: Test 결과 예외처리 부분 수정
mlngwan May 14, 2024
78c9949
Test: 리팩토링 후 새로운 Test 코드 작성
mlngwan May 14, 2024
d6e7d1c
Test: 테스트코드 상수 설정 및 정렬
mlngwan May 15, 2024
40c8548
Test: 테스트코드 상수 설정, 및 개행 수정, 중첩 테스트 클래스 설정
mlngwan May 15, 2024
b115121
Test: 테스트코드 상수 설정, 및 개행 수정, 중첩 테스트 클래스 설정
mlngwan May 15, 2024
4fb6e5c
Refactor: 사용자의 입력을 받는 inputView EOF처리
mlngwan May 15, 2024
8de5ddc
Refactor: 파일의 끝에 개행을 통해 EOF 처리
mlngwan May 22, 2024
4601969
Test: 컨벤션 지켜지지 않은 부분 수정
mlngwan May 22, 2024
f185842
Refactoring: 불필요한 부분 제거로 코드 간결화
mlngwan May 22, 2024
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
2 changes: 2 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,10 @@ repositories {
dependencies {
testImplementation platform('org.junit:junit-bom:5.9.1')
testImplementation('org.junit.jupiter:junit-jupiter')
testImplementation("org.assertj:assertj-core:3.20.2")
}

test {
useJUnitPlatform()
}

65 changes: 65 additions & 0 deletions src/main/java/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
## Step1 & Step2 (초간단 계산기 구현 및 테스트)
### 기능 요구사항
인자 2개를 받아 사칙연산을 할 수 있는 계산기를 구현한다.
사칙연산과 매칭되는 4개의 메서드를 제공한다.
계산된 결과는 정수를 반환한다.

### 새로운 프로그래밍 요구사항
메인 메서드는 만들지 않는다.

### 단위 테스트
작은 단위로 테스트 할 것.

### ToDo
- 사칙연산 구현하기
- 최대한 MVC 구조로 구현하기
- JUnit 공부하기
- JUnit 활용하기
- 단위 테스트 구현하기

## Step 3 (문자열 계산기)
### 기능 요구사항
- 기본적으로 쉼표(,)나 콜론(:)을 구분자로 가지는 경우
- 기본 구분자로 분리한 각 숫자 합을 반환
- (예: "" => 0, "1,2" => 3, "1,2:3" => 6)
- 커스텀 구분자 지정 가능, "//"와 "\n" 사이에 위치하는 문자를 사용하는 경우
-커스텀 구분자로 분리해서 각 숫자 합을 반환
- (예: "//;\n1;2;3" => 구분자:";", 결과로 6 반환)
- 문자열 계산기에 숫자 이외의 값 전달 경우 RuntimeException 예외 throw
- 문자열 계산기에 음수를 전달하는 경우 RuntimeException 예외 throw

### 새로운 프로그래밍 요구사항
- 구현한 문자열 계산기가 예상한대로 작동하는지 JUnit5 활용하여 테스트 자동화
- 조금 더 복잡한 도메인 대상으로 테스트 작성 경험

### 기존 프로그래밍 요구사항
- 메인 메서드 작성하지 않기

### ToDo
- 문자열 계산기 구현하기
- MVC 구조로 작성하기
- JUnit5 기반 테스트 작성하기
- 필요기능?
- AssertJ 기반 테스트 작성하기
- AssertJ 관련 학습하기
- AssertJ로 구현하기

## Step4 리팩토링
### 코드 작성 시 주의할 점
- 클래스 첫 줄에는 개행 넣기 -> 코드 컨벤션 (개행 알아보기)
- 코드에 EOF 발생 -> 무엇인지, 처리법
- 코드 내부에 사용하는 메서드의 접근 제어자 설정
- 상수 처리 및 네이밍
- 메서드 명은 동사로 시작하기
- static 사용이유
- test code 네이밍 알아보기
- test code given-when-then 알아보기

### 초간단 계산기
- 사용자의 입력에 따라서 해당 연산 실행하게 바꾸기
- 음수일 때 예외 추가
- 나누는 수가 0일때 예외 처리
- view에 로직을 처리하지 않게 하기 -> model에서 처리하기

### 문자열 계산기
- sum 메서드 처리
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package simpleCalculator.controller;

import simpleCalculator.model.Calculator;
import simpleCalculator.model.StringCalculator;
import simpleCalculator.view.InputView;
import simpleCalculator.view.OutView;

public class CalculatorController {

Choose a reason for hiding this comment

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

해당 클래스 외에도 첫줄 개행 추가해주세요

Copy link
Author

@mlngwan mlngwan May 15, 2024

Choose a reason for hiding this comment

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

네 수정하겠습니다!


private InputView inputView;
private OutView outView;
private Calculator calculator;
private StringCalculator stringCalculator;

public CalculatorController() {
this.inputView = new InputView();
this.outView = new OutView();
this.calculator = new Calculator();
this.stringCalculator = new StringCalculator();
}

private void runSimpleCalculator() {
String input = inputView.getSimpleNumber();
calculator.setNumber(input);

int resultAdd = calculator.addNumbers();
int resultSub = calculator.subNumbers();
int resultDiv = calculator.divideNumbers();
int resultMul = calculator.multipleNumbers();

outView.printResult(resultAdd);
outView.printResult(resultSub);
outView.printResult(resultDiv);
outView.printResult(resultMul);
}

private void runStringCalculator() {
String input = inputView.getStringNumber();
int result = stringCalculator.add(input);

outView.printResult(result);
}
}
68 changes: 68 additions & 0 deletions src/main/java/simpleCalculator/model/Calculator.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
package simpleCalculator.model;

public class Calculator {

private static final int ZERO = 0;
private static final int ONE = 1;
private static final int TWO = 2;

private int num1;
private int num2;

private boolean checkHowManyInput(String[] inputList) {
return inputList.length != TWO;
}

private String[] splitList(String input) {
return input.split(",");
}

private int convertToInt(String input) {
int number = Integer.parseInt(input);
if (number < ZERO) {
throw new RuntimeException("음수는 입력할 수 없습니다.");
}
return number;
}

private int[] convertToIntList(String[] inputList) {
try {
int[] numberList = new int[inputList.length];
for (int i = ZERO; i < inputList.length; i++) {
numberList[i] = convertToInt(inputList[i]);
}
return numberList;
} catch (NumberFormatException e) {
throw new RuntimeException("숫자가 아닌 다른 형식이 포함되어 있습니다.");
}
}

public void setNumber(String input) {
String[] inputList = splitList(input);
if(checkHowManyInput(inputList)) {
throw new RuntimeException("2개의 숫자를 입력해주세요.");
}
int[] numbers = convertToIntList(inputList);
this.num1 = numbers[ZERO];
this.num2 = numbers[ONE];
}

public int addNumbers() {
return num1 + num2;
}

public int subNumbers() {
return num1 - num2;
}

public int divideNumbers() {
if (num2 == 0) {
throw new RuntimeException("0으로 나누기는 불가합니다.");
}
return num1 / num2;
}

public int multipleNumbers() {
return num1 * num2;
}
}

Choose a reason for hiding this comment

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

EOF가 발생하네요 검색하셔서 해결해주세요~

Copy link
Author

Choose a reason for hiding this comment

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

EOF에 대해 맞게 이해 했는지와 궁금한 점이 생겼습니다.
입력의 개수가 정해지지 않은 경우에만 더 이상 입력이 없게 하기 위해 사용하는 것으로 이해했습니다.
scanner.close()와 차이점이 무엇인가요??

Choose a reason for hiding this comment

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

scanner.close()는 resource를 풀어주는 거라 다른 결이긴 합니다!
해당 링크 참고해보시면 좋을 것 같아요!

59 changes: 59 additions & 0 deletions src/main/java/simpleCalculator/model/StringCalculator.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package simpleCalculator.model;

public class StringCalculator {

private static final String SEPARATOR_DEFAULTS = ",|:";
private static final int ZERO = 0;

private boolean checkBlank(String input) {
return input == null || input.isEmpty();
}

private String[] splitInput(String input) {
if (input.startsWith("//")) {
return splitByCustom(input);
}
return input.split(SEPARATOR_DEFAULTS);
}

private String[] splitByCustom(String input) {
String[] separates = input.split("\n", 2);
String custom = separates[ZERO].substring(2);
return separates[1].split(custom);
}

private int[] listToInt(String[] inputList) {
try {
int[] numberList = new int[inputList.length];
for (int i = ZERO; i < inputList.length; i++) {
numberList[i] = convertToInt(inputList[i]);
}
return numberList;
} catch (NumberFormatException e) {
throw new RuntimeException("숫자가 아닌 다른 형식이 포함되었습니다.");
}
}

private int convertToInt(String input) {
int number = Integer.parseInt(input);
if (number < ZERO) {
throw new RuntimeException("음수는 입력할 수 없습니다.");
}
return number;
}

private int sum(int[] inputList) {
int total = ZERO;
for (int number : inputList) {
total += number;
}
return total;
}

public int add(String input) {
if (checkBlank(input)) {
return ZERO;
}
return sum(listToInt(splitInput(input)));
}
}

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.

보내주신 내용 확인해서 파일마다 끝에 한 줄 비워두는 방식으로 수정했습니다!

28 changes: 28 additions & 0 deletions src/main/java/simpleCalculator/view/InputView.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package simpleCalculator.view;

import java.util.Scanner;

public class InputView {

private Scanner scanner;

Choose a reason for hiding this comment

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

private,
private final,
private static final,
private static

각각 차이는 무엇일까요?

Copy link
Author

Choose a reason for hiding this comment

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

private는 해당 클래스 내부에서만 접근 가능하게 만들어주는 접근 제어자 입니다.
private final은 한 번 값이 설정되면 그 값이 고정되며 인스턴스 별로 각기 다른 값을 가질 수 있습니다.
그리고 private에 의해 해당 클래스 내부에서만 접근 가능합니다.
private static final은 모든 인스턴스가 사용하는 고정된 값을 할당할 때 사용합니다. 주로 상수 설정에 사용합니다.
private static은 객체 생성 없이 사용 가능한 필드나 메서드들을 생성하고 싶을 때 사용합니다.
클래스의 모든 인스턴스가 접근 가능하지만 private에 의해 해당 클래스 내부에서만 접근 가능합니다.

위와 같이 이해하고 있는데 잘못된 부분이 있을까요?


public InputView() {
this.scanner = new Scanner(System.in);
}

public String getSimpleNumber() {
System.out.println("계산할 내용을 입력해주세요.(숫자,연산자,숫자 형식)");
while (scanner.hasNextLine()) {
return scanner.nextLine();
}
return null;
}

public String getStringNumber() {
System.out.println("기본(, :)이나 커스텀 구분자(;)를 가지는 문자열을 입력해주세요. (예: 1,2 => 3, //;\\n1;2;3 => 6 반환)");
while (scanner.hasNextLine()) {
return scanner.nextLine();
}
return null;

Choose a reason for hiding this comment

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

return scanner.next(); 이렇게 해도 될 것 같아요!

Copy link
Author

Choose a reason for hiding this comment

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

EOF를 잘못 이해하고 나름대로 resource를 풀어주려고 작성했습니다.
보내주신 내용 확인하고 수정 완료했습니다!

}
}
8 changes: 8 additions & 0 deletions src/main/java/simpleCalculator/view/OutView.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package simpleCalculator.view;

public class OutView {

public void printResult(int result) {
System.out.println("계산 결과: " + result);
}
}
77 changes: 77 additions & 0 deletions src/test/java/calculator/CalculatorTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
package calculator;

import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
import simpleCalculator.model.Calculator;

import static org.junit.jupiter.api.Assertions.*;

public class CalculatorTest {

private static final int EXPECT_VALUE = 3;
private Calculator calculator;

Choose a reason for hiding this comment

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

Suggested change
private static final int EXPECT_VALUE = 3;
private Calculator calculator;
private static final int EXPECT_VALUE = 3;
private Calculator calculator;

Copy link
Author

Choose a reason for hiding this comment

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

수정 완료했습니다!


@BeforeEach
void setCalculator() {
calculator = new Calculator();
}

@DisplayName("연산기능 테스트")
@Nested
class functionTest {

@DisplayName("더하기")
@Test
void testAdd() {
calculator.setNumber("1,2");
assertEquals(EXPECT_VALUE, calculator.addNumbers());
}

@DisplayName("빼기")
@Test
void testSub() {
calculator.setNumber("4,1");
assertEquals(EXPECT_VALUE, calculator.subNumbers());
}

@DisplayName("나누기")
@Test
void testDiv() {
calculator.setNumber("9,3");
assertEquals(EXPECT_VALUE, calculator.divideNumbers());
}

@DisplayName("곱하기")
@Test
void testAMul() {
calculator.setNumber("3,1");
assertEquals(EXPECT_VALUE, calculator.multipleNumbers());
}
}

@DisplayName("예외처리 테스트")
@Nested
class exceptionTest {

@DisplayName("0으로 나누기를 시도한 경우")
@Test
void testDivideByZero() {
calculator.setNumber("10,0");
assertThrows(RuntimeException.class, () -> calculator.divideNumbers());
}

@DisplayName("입력을 2개 미만으로 시도한 경우")
@Test
void testInputUnderTwo() {
assertThrows(RuntimeException.class, () -> calculator.setNumber("1"));
}

@DisplayName("입력을 2개 초과로 시도한 경우")
@Test
void testInputOverTwo() {
assertThrows(RuntimeException.class, () -> calculator.setNumber("1,2,3"));
}
}
}
Loading