-
Notifications
You must be signed in to change notification settings - Fork 50
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
[라빈] 온보딩 - 학습 테스트, 단위 테스트 #3
Changes from all commits
ed7ba12
b7f56bf
4646843
3994dee
db637c0
1da46a8
43d67f6
75191ca
f5b3b85
19caade
006eded
470960a
b3fbab4
1985f2b
061557d
9d2cac8
d5d53d5
4f46d30
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,36 @@ | ||
# java-calculator | ||
문자열 계산기 미션 저장소 | ||
|
||
## 우아한테크코스 코드리뷰 | ||
* [온라인 코드 리뷰 과정](https://github.com/woowacourse/woowacourse-docs/blob/master/maincourse/README.md) | ||
## 기능적 요구사항 | ||
- 문자열을 입력 받아 공백 단위로 split 하는 함수를 만든다 | ||
- 입력이 정상적인지 확인 | ||
- 입력이 없는지 | ||
- 숫자와 연산자 외의 다른 문자가 있는지 | ||
- split 된 결과가 정상적인지 확인 | ||
- 숫자와 연산자의 순서가 맞는지 | ||
|
||
- 사칙연산을 하는 함수를 만든다 | ||
- 나눗셈의 경우 0으로 나누는 경우에 대한 예외 처리 | ||
- 입력 값이 자료형의 범위를 넘어 가는 경우에 대한 예외 처리 | ||
|
||
- split 된 결과 값이 순서대로 연산이 되는 함수를 만든다 | ||
|
||
- 연산 결과를 출력하는 함수를 만든다 | ||
|
||
- 단위별로 테스트 하는 함수를 만든다 | ||
- split 테스트를 진행한다 | ||
- 입력으로 null, 공백, 유효하지 않은 double 범위의 수, 숫자와 연산자 외의 문자열 | ||
- split 할 수 없는 문자열, 숫자와 연산자 순서가 바뀐 문자열, 정상 계산식 | ||
- 사칙연산 테스트 | ||
- 사칙연산의 결과 값이 실제 값과 맞는지 테스트 | ||
- 0으로 나누었을 때, double 범위를 넘어가는 결과 값 | ||
|
||
|
||
## 비기능적 요구사항 | ||
- indent 2까지 허용한다. | ||
- 메소드는 15줄 까지 허용한다. | ||
- switch문 사용하지 않는다. | ||
- 하드코딩하지 않는다. | ||
- 변수와 메소드 명명은 컨벤션에 따른다. | ||
- 자바 코드 컨벤션을 지키면서 프로그래밍 한다. | ||
- 함수의 인자 수를 3개까지만 허용한다. |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
package calculator; | ||
|
||
public class Calculator { | ||
public double calculate(String[] splitedInput) { | ||
double left = Double.valueOf(splitedInput[0]); | ||
for (int i = 1; i < splitedInput.length; i = i + 2) { | ||
String operator = splitedInput[i]; | ||
double right = Double.valueOf(splitedInput[i + 1]); | ||
left = Operator.find(operator).calculate(left, right); | ||
} | ||
return left; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
package calculator; | ||
|
||
public class Constant { | ||
public final static int ZERO = 0; | ||
|
||
public final static String BLANK = " "; | ||
public final static String EMPTY_STRING = ""; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
package calculator; | ||
|
||
public class Main { | ||
public static void main(String[] args) { | ||
UserInputScanner userInputScanner = new UserInputScanner(); | ||
Calculator calculator = new Calculator(); | ||
Output output = new Output(); | ||
|
||
try { | ||
String[] splitString = userInputScanner.splitUserInputString(); | ||
double result = calculator.calculate(splitString); | ||
output.printResult(result); | ||
} catch (Exception e) { | ||
System.out.println(e.getMessage()); | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
package calculator; | ||
|
||
import java.util.Arrays; | ||
import java.util.function.BiFunction; | ||
|
||
public enum Operator { | ||
PLUS("+", | ||
(left, right) -> (left + right)), | ||
MINUS("-", | ||
(left, right) -> (left - right)), | ||
MULTIPLICATION("*", | ||
(left, right) -> (left * right)), | ||
DIVISION("/", | ||
(left, right) -> (left / right)); | ||
|
||
private String symbol; | ||
private BiFunction<Double, Double, Double> expression; | ||
|
||
Operator(String symbol, BiFunction<Double, Double, Double> expression) { | ||
this.symbol = symbol; | ||
this.expression = expression; | ||
} | ||
|
||
private String getSymbol() { | ||
return this.symbol; | ||
} | ||
|
||
public static Operator find(String operator) { | ||
return Arrays.stream(Operator.values()) | ||
.filter(op -> op.getSymbol().equals(operator)) | ||
.findFirst() | ||
.get(); | ||
} | ||
|
||
public double calculate(double left, double right) { | ||
return expression.apply(left, right); | ||
} | ||
|
||
public static boolean isRightOperator(String operator) { | ||
return Arrays.stream(Operator.values()) | ||
.anyMatch(op -> op.getSymbol().equals(operator)); | ||
} | ||
|
||
public static boolean isDivisionOperator(String operator) { | ||
return "/".equals(operator); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
package calculator; | ||
|
||
public class Output { | ||
public void printResult(double result) { | ||
System.out.println("결과 값은 : " + result); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
package calculator; | ||
|
||
import java.util.Scanner; | ||
|
||
public class UserInputScanner { | ||
private ValidityInspector validityInspector = new ValidityInspector(); | ||
private Scanner scanner = new Scanner(System.in); | ||
|
||
private String inputStringToUser() { | ||
System.out.print("계산식을 입력하시오: "); | ||
String inputLine = scanner.nextLine(); | ||
validityInspector.checkUserInputIsBlankOrEmpty(inputLine); | ||
return inputLine; | ||
} | ||
|
||
public String[] splitUserInputString() { | ||
String input = inputStringToUser(); | ||
String[] splitInput = input.split(Constant.BLANK); | ||
validityInspector.checkCanConvertUserInputToNumberAndOperator(splitInput); | ||
return splitInput; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
package calculator; | ||
|
||
public class ValidityInspector { | ||
public void checkUserInputIsBlankOrEmpty(String input) { | ||
if (isBlank(input) || isEmpty(input)) { | ||
throw new IllegalArgumentException("공백 또는 빈 문자열을 입력하셨습니다."); | ||
} | ||
} | ||
|
||
private boolean isEmpty(String input) { | ||
return input.equals(Constant.EMPTY_STRING); | ||
} | ||
|
||
private boolean isBlank(String input) { | ||
return input.equals(Constant.BLANK); | ||
} | ||
|
||
public void checkCanConvertUserInputToNumberAndOperator(String[] splitedInput) { | ||
checkSplitedInputEmpty(splitedInput); | ||
String firstClause = splitedInput[0]; | ||
checkCorrectDoubleNumber(firstClause); | ||
try { | ||
for (int i = 1; i < splitedInput.length; i = i + 2) { | ||
String operator = splitedInput[i]; | ||
String secondClause = splitedInput[i + 1]; | ||
checkDivideByZero(operator, secondClause); | ||
checkCorrectOperator(operator); | ||
checkCorrectDoubleNumber(secondClause); | ||
} | ||
} catch (ArrayIndexOutOfBoundsException e) { | ||
throw new ArrayIndexOutOfBoundsException("잘못된 계산식을 입력하였습니다."); | ||
} | ||
} | ||
|
||
private void checkCorrectDoubleNumber(String s) { | ||
try { | ||
Double.valueOf(s); | ||
} catch (Exception e) { | ||
throw new IllegalArgumentException("잘못된 수를 입력하였습니다."); | ||
} | ||
} | ||
|
||
private void checkCorrectOperator(String s) { | ||
if (!Operator.isRightOperator(s)) { | ||
throw new IllegalArgumentException("잘못된 연산자를 입력하였습니다."); | ||
} | ||
} | ||
|
||
private void checkSplitedInputEmpty(String[] splitedInput) { | ||
if (splitedInput.length == 0) { | ||
throw new IllegalArgumentException("공백을 입력하였습니다."); | ||
} | ||
} | ||
|
||
private void checkDivideByZero(String operator, String secondClause) { | ||
if (Operator.isDivisionOperator(operator) && Integer.toString(Constant.ZERO).equals(secondClause)) { | ||
throw new IllegalArgumentException("0으로 나누는 식을 입력하셨습니다."); | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
package calculator; | ||
|
||
import org.assertj.core.api.Assertions; | ||
import org.junit.jupiter.api.BeforeEach; | ||
import org.junit.jupiter.api.Test; | ||
import org.junit.jupiter.params.ParameterizedTest; | ||
import org.junit.jupiter.params.provider.ValueSource; | ||
|
||
public class CalculatorTest { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. MethodSource 이 외에도 여러가지 ParameterizedTest 를 위한 Source 들이 제공됩니다 :) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. MethodSource 로 테스트 코드를 작성했었던 이유는 이전에 테스트를 할 때 Double.toString() 을 이용해서 테스트를 해보려고 했었기 때문이었습니다. 목적에 맞는 Source 를 사용하도록 코드를 변경했습니다. 잘 몰랐던 부분인데 감사합니다 :) |
||
private Calculator calculator; | ||
private ValidityInspector validityInspector; | ||
|
||
@BeforeEach | ||
public void setUp() { | ||
calculator = new Calculator(); | ||
validityInspector = new ValidityInspector(); | ||
} | ||
|
||
@ParameterizedTest | ||
@ValueSource(strings = {" ", ""}) | ||
public void checkUserInputIsBlankOrEmptyTest(String input) { | ||
Assertions.assertThatThrownBy(() -> { | ||
validityInspector.checkUserInputIsBlankOrEmpty(input); | ||
}).isInstanceOf(IllegalArgumentException.class) | ||
.hasMessageContaining("공백 또는 빈 문자열을 입력하셨습니다."); | ||
} | ||
|
||
@ParameterizedTest | ||
@ValueSource(strings = {" ", "q + w + e", "1+2+3", "+ + 2", "1 abcd 2", "2 * 65 / 0", "2 + 3/", "/1 + 55", "1 + a3"}) | ||
public void checkCanConvertUserInputToNumberAndOperatorTest(String input) { | ||
String[] splitData = input.split(Constant.BLANK); | ||
Assertions.assertThatThrownBy(() -> { | ||
validityInspector.checkCanConvertUserInputToNumberAndOperator(splitData); | ||
}).isInstanceOf(IllegalArgumentException.class); | ||
} | ||
|
||
@Test | ||
public void addTest() { | ||
String[] numericalExpression = {"1", "+", "2"}; | ||
Double result = calculator.calculate(numericalExpression); | ||
Assertions.assertThat(result).isEqualTo(3); | ||
} | ||
|
||
@Test | ||
public void subtractTest() { | ||
String[] numericalExpression = {"1", "-", "2"}; | ||
Double result = calculator.calculate(numericalExpression); | ||
Assertions.assertThat(result).isEqualTo(-1); | ||
} | ||
|
||
@Test | ||
public void multipleTest() { | ||
String[] numericalExpression = {"1", "*", "2"}; | ||
Double result = calculator.calculate(numericalExpression); | ||
Assertions.assertThat(result).isEqualTo(2); | ||
} | ||
|
||
@Test | ||
public void divideTest() { | ||
String[] numericalExpression = {"1", "/", "2"}; | ||
Double result = calculator.calculate(numericalExpression); | ||
Assertions.assertThat(result).isEqualTo(0.5d); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
package study; | ||
|
||
import org.assertj.core.api.Assertions; | ||
import org.junit.jupiter.api.BeforeEach; | ||
import org.junit.jupiter.api.Test; | ||
import org.junit.jupiter.params.ParameterizedTest; | ||
import org.junit.jupiter.params.provider.CsvSource; | ||
import org.junit.jupiter.params.provider.ValueSource; | ||
|
||
import java.util.HashSet; | ||
import java.util.Set; | ||
|
||
import static org.junit.jupiter.api.Assertions.assertTrue; | ||
|
||
public class SetTest { | ||
private Set numbers; | ||
|
||
@BeforeEach | ||
void setUp() { | ||
numbers = new HashSet<>(); | ||
numbers.add(1); | ||
numbers.add(1); | ||
numbers.add(2); | ||
numbers.add(3); | ||
} | ||
|
||
@Test | ||
void sizeTest() { | ||
int size = numbers.size(); | ||
Assertions.assertThat(size).isEqualTo(4); | ||
} | ||
|
||
@ParameterizedTest | ||
@ValueSource(ints = {1, 1, 2, 3}) | ||
void containTest(int number) { | ||
assertTrue(numbers.contains(number)); | ||
} | ||
|
||
@ParameterizedTest | ||
@CsvSource(value = {"ravie-RAVIE", "Lavine-LAVINE", "orange-ORANKE", "dog-DoG"}, delimiter = '-') | ||
void equalUpperCase(String input, String upperCase){ | ||
Assertions.assertThat(upperCase).isEqualTo(input.toUpperCase()); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
package study; | ||
|
||
import org.junit.jupiter.api.DisplayName; | ||
import org.junit.jupiter.api.Test; | ||
import org.assertj.core.api.Assertions; | ||
|
||
public class StringTest { | ||
@Test | ||
void split() { | ||
String value = "1,2"; | ||
String[] result = value.split(","); | ||
Assertions.assertThat(result).contains("1"); | ||
Assertions.assertThat(result).contains("2"); | ||
String[] temp = {"1", "2"}; | ||
Assertions.assertThat(result).containsExactly(temp); | ||
} | ||
|
||
@Test | ||
void substring() { | ||
String value = "(1,2)"; | ||
String result = value.substring(1, value.length() - 1); | ||
Assertions.assertThat(result).contains("1,2"); | ||
} | ||
|
||
@Test | ||
@DisplayName("charAt method out of bounds test") | ||
void charAtTest() { | ||
String value = "abc"; | ||
Assertions.assertThatThrownBy(() -> { | ||
value.charAt(10); | ||
}).isInstanceOf(StringIndexOutOfBoundsException.class).hasMessageContaining("String index out of range"); | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
잘못된 입력에 대한 예외는 처리해줬으면 더 좋았겠네요 :)