사칙연산 계산기 구현
package org.example;
import org.example.calculate.PositiveNumber;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
import java.util.stream.Stream;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatCode;
import static org.junit.jupiter.params.provider.Arguments.arguments;
/**요구사항
• 간단한 사칙연산을 할 수 있다.
• 양수로만 계산할 수 있다.
• 나눗셈에서 0을 나누는 경우 IllegalArgument 예외를 발생시킨다.
• MVC패턴(Model-View-Controller) 기반으로 구현한다.
*/
public class CalculatorTest {
// 1 + 2 -----> Calculator
// 3 <-----
@DisplayName("덧샘 연산을 정상적으로 수행한다.")
@ParameterizedTest
@MethodSource("formulaAndResult")
void calculatorTest(int operand1, String operator,int operand2,int result) {
int calculateResult = Calculator.calculator(new PositiveNumber(operand1) , operator,new PositiveNumber(operand2));
assertThat(calculateResult).isEqualTo(result);
}
private static Stream<Arguments> formulaAndResult() {
return Stream.of(
arguments(1, "+" ,2,3),
arguments(1, "-" ,2,-1),
arguments(4, "*" ,2,8),
arguments(4, "/" ,2,2)
);
}
}
- org.example.CalculatorTest 클래스 : 테스트 케이스를 정의하는 곳. 이클래스는 Calculator 클래스를 테스트한다.
여기서 테스트 케이스란 소프트웨어의 특정 기능, 모듈, 또는 시스템이 정확하게 작동하는지 확인하기 위한 입력 값,실행조건, 예상 결과 및 테스트 코드로 이루어진 단위입니다. 테스트 케이스는 소프트웨어 개발과 품질 보증 과정에서 중요한 역활을 한다.
CalculatorTest 클래스의 각 메소드는 테스트 케이스를 나타낸다. 예를 들어 calculatrotTest 메소드는 덧셈 연산을 정상적으로 수행한다. 라는 테스트 케이스를 정의한다. 이 특정 테스트 케이스에 대한 설명은
입력 값 : operand1 = 1 , operator = "+" ,operand2 = 2
실행 조건 : Calculator.calculator(new PosittiveNumber(operand1), operator, new PosittiveNumber( operand2)) 를 호출
예상 결과 : '3'
이테스트 케이스는 주어진 입력 값으로 두 양수와 덧셈 연산을 수행했을 때, 예상된 결과가 '3' 이어야 함을 확인하는 역확을 한다. 다른 calculatorTest 메소드도 다양한 입력 조합에 대한 테스트 케이스를 나타낸다.
테스트 케이스는 코드의 신뢰성을 확인하고 버그를 발견하는데 도움을 주며 , 변경사항이 코드에 영향을 미치지 않는지 확인하는데 사용된다. 이를 통해 소프트웨어의 안정성을 높이고 문제를 미리 발견할 수 있다.
@MethodSource("formulaAndResult") 어노테이션은 매개변수화된 테스트에 대한 인수를 제공하는 메소드를 지정한다.
formulaAndResult 메소드는 테스트에 사용되는 다양한 입력 및 예상 결과를 제공한다.
추가 설명 - JUnit5 에서 제공하는 매개변수화된 테스트를 수행할 때 사용되는 어노테이션 이다.
테스트 메소드에 필요한 입력 값을 제공하는 메소드를 지정할 수 있다.
여기서 formulaAndResult 메소드는 테스트 케이스에 피요한 여러 입력 값을 생성하고 반환하는 역활을 한다.
이메소드는 @MethodSource 어노테이션을 사용하여 테스트 메소드에 데이터를 공급함.
테스트 케이스에 필요한 여러 입력 값을 생성하려면 formulaAndResult 메소드는 Stream<Arguments> 를 반환해야 한다.
Arguments 는 JUnit5에서 사용되는 메소드의 인수로 전달 할 값의 묶음을 나타내는 클래스이다.
formulaAndResult 메소드는 Stream.of(arguments(...))를 사용하여 Arguments 객체를 생성하고 반환하고. 각 arguments 메소드 호출은 한 개의 테스트 케이스에 대한 입력 값을 나타내며, 메소드의 매개변수에 따라서 입력 값이 설정된다.
예를 들어
return Stream.of(
arguments(1, "+", 2, 3), // 테스트 케이스 1
arguments(1, "-", 2, -1), // 테스트 케이스 2
arguments(4, "*", 2, 8), // 테스트 케이스 3
arguments(4, "/", 2, 2) // 테스트 케이스 4
);
arguments(1, "+", 2, 3)는 첫 번째 테스트 케이스를 나타내며
operand1에 1,
operator에 "+" ,
operand2에 2,
result에 3의 값을 제공
formulaAndResult 메소드는 이러한 Arguments 객체를 Stream 으로 반환하고 , 이러한 입력 값이 @ParameterizedTest 어노테이션이 지정된 테스트 메소드로 전달되어 실행된다.
테스트는 assertThat 및 isEqualTo를 사용하여 예상 결과와 실제 결과를 비교하고 이를 통해 코드가 올바른 결과를 생성하는지 확인한다
assertThat :
1. AssertJ 라이브러리에서 제공하는 Assertion 시작하는 메소드이다.
2. 이 메소드를 사용하여 Assertion Chain을 시작하고 Assertion을 연속적으로 연결할 수 있다.
3. 실제 값에 대한 검사를 시작하며 이 값은 테스트에서 확인하려는 값이다.
isEqualTo :
1. 예상 결과와 비교하여 두 값이 같은지를 확인한다 예를 들어 assertThat(actualValue).isEqualTo(expectedValue)와 같이 사용된다 .
2. 이 메소드는 두 값이 동일한 경우에는 테스트가 성공하고 다른 경우에는 테스트가 실패한다.
3. 예를 들어
int actualResult = Calculator.calculator(new PositiveNumber(1), "+", new PositiveNumber(2));
int expectedResult = 3;
// AssertJ를 사용한 어서션
assertThat(actualResult).isEqualTo(expectedResult);
package org.example.calculate;
public interface NewArithmeticOperator {
boolean supports(String operator);
int calculate(PositiveNumber operand1, PositiveNumber operand2);
}
새로운 산술 연산자를 정의하는 데 사용된다.
boolean supports(String operator) : 이 메서드는 주어진 연산자(operator)가 새로운 산술 연산자를 지원하는지 여부를 판단하는데 사용 된다. 메서드는 boolean 값을 반환하며, 연산자를 지원하는 경우 true를 반환하고 그렇지 않은 경우 false를 반환한다.
int calculate(PositiveNumber operand1, PositiveNumber operand2) : 이 메서드는 두 개의 양의 숫자 (operand1 과 operand2)를 받아서 주어진 연산자로 계산을 수행하는 메서드이며 메서드는 계산 결과로 정수를 반환한다.
이 인터페이스는 다양한 산술 연산자를 추가하고, 각 연산자에 대한 지원 여부를 확인하며 주어진 연산자로 계산을 수행하는 클래스에서 구현 될 수 있다. 예를 들어 덧셈,뺼셈,곱셈,나눗셈과 같은 다양한 연산자를 구현할 수 있으며 supports 메서드를 통해 지원 여부를 확인하고 , calculate 메서드를 통해 계산을 수행할 수 있다.
이 인터페이스는 다형성을 통해 다양한 연산자를 처리하고 코드의 확장성과 유지보수성을 향상시키는 데 도움이 된다.
package org.example;
import org.example.calculate.PositiveNumber;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;
import static org.assertj.core.api.Assertions.assertThatCode;
public class PositiveNumberTest {
@ParameterizedTest
@ValueSource(ints = {0,-1})
void createTest(int value) {
assertThatCode(()-> new PositiveNumber(value))
.isInstanceOf(IllegalArgumentException.class)
.hasMessage("0또는 음수를 전달할 수 없습니다.");
}
}
이 클래스는 PositiveNumber 클래스의 특정 메서드를 테스트 하기 위한 테스트 케이스를 정의하는 곳이다.
@ValueSource(ints = {0,-1}) 어노테이션 : createTest 메서드를 테스트할 때 사용할 입력 값을 제공한다
여기서 {0 , 1} 는 두 가지 입력 값인 0과 -1을 나타낸다
좀 더 자세히 설명하면 @ValueSource 어노테이션은
@ValueSource(data_type = {values}) 과 같이 사용된다.
여기서 ints는 정수 데이터 타입을 나태내고 이것은 테스트 메소드에 전달할 데이터의 타입을 지정하는 부분이다.
{values}는 중괄호 내부에 여러 입력 값들을 배열 형태로 나열하는 부분이다. 이부분에서는 테스트 메소드를 여러 번 실행할 때 사용될 입력 값의 목록을 제공한다. 위의 예에서는 0 과 -1 두 개의 입력값을 나열했다.
@ValueSource 어노테이션에서 정의한 입력 값들을 받아 실행된다. 각 입력 값에 대해 테스트 메소드가 실행된다.
예를 들어, 위의 코드에서 createTest 메소드는 @ValueSource 어노테이션에서 정의한 입력 값인 0과 -1을 받아서 두 번 실행 처음에는 value가 0으로 설정되고, 두 번째 실행에서 value가 -1로 설정 따라서 같은 테스트 메소드가 다양한 입력 값에 대해 반복 실행된다.
package org.example.calculate;
public class PositiveNumber {
private final int value;
public PositiveNumber(int value) {
validate(value);
this.value = value;
}
private void validate(int value) {
if(isNegativeNumber(value)) {
throw new IllegalArgumentException("0또는 음수를 전달할 수 없습니다.");
}
}
private boolean isNegativeNumber(int value) {
return value <= 0;
}
public int toInt() {
return value;
}
}
private final int value : 이 필드는 PositiveNumber 객체가 나타내는 양의 정수 값을 저장한다.
final 키워드로 인해 한번 설정되면 변경할 수 없다.
public PositiveNumber(int value) : 이 생성자는 PositiveNumber 객체를 생성할 때 호출된다. 생성자는 입력으로 받은
value 를 점증한 후 검증을 통과하면 해당 값을 value 필드에 설정한다.
private void validate(int value) : 이 메서드는 value 를 검증하는 데 사용된다 입력 값이 0또는 음수인 경우 즉 양수가 아닌 경우 예외를 발생시키는데 사용 된다 이 메서드는 isNegativeNumber 메서드를 호출하여 검증을 수행한다.
private boolean isNegativeNumber(int value) : 이 메서드는 주어진 value 가 음수인지 확인한다 value 가 0 이하인 경우 true 를 반환하고 그렇지 않으면 false 를 반환한다.
public int toInt() : 이 메서드는 PositiveNumber 객체를 int 데이터 타입으로 변환하여 반환한다 즉 PositiveNumber 객체가 나타내는 양의 정수 값을 반환한다.
결론적으로 PositiveNumber 클래스가 양수만을 표현하고, 음수 또는 0을 거부하는 역확을 수행하는 클래스이다
객체 생성할 때 입력값을 검증하여 안전성을 높이고 양의 정수 값을 추출하는 메서드를 제공한다 이러한 클래스는
예외를 사용하여 부적절한 입력을 처리하고 , 양수 데이터를 보다 안전하게 다룰 수 있도록 도와준다.
package org.example.calculate;
public class AdditionOperator implements NewArithmeticOperator {
@Override
public boolean supports(String operator) {
return "+".equals(operator);
}
@Override
public int calculate(PositiveNumber operand1, PositiveNumber operand2) {
return operand1.toInt() + operand2.toInt();
}
}
이 클래스는 NewArithmeticOperator 인터페이스를 구현하고 있어서 supports , calculate 메서드를 반드시 구현해야한다.
supports(String operator) 메서드 : 이메서드는 주어진 연산자 (operator) 가 덧셈 연산을 지원 하는지 확인하는 역활을한다.
만약 연산자가 "+" 와 같다면 , 즉 덧셈 연산을 지원한다면 true 를 반환하고 그렇지 않으면 false를 반환한다.
calculate(PositiveNumber operand1, PositiveNumber operand2) 메서드 : 이 메서드는 두개의 PositiveNumber 객체인 operand1 과 operand2 를 받아서 덧셈 연산을 수행한다
operand1.toInt()와 operand2.toInt()를 통해 각각의 PositiveNumber 객체를 정수 값으로 변환한 후 이 두 값을 더하여 결과를 반환한다.
supports 메서드를 사용하여 주어진 연산자가 덧셈을 지원 하는지 확인하고 , calculate 메서드를 사용하여 실제 덧셈 연산을 수행한다 이러한 디자인은 NewArithmeticOperator 인터페이스를 따르는 다른 연산자 클래스들을 추가할 수 있도록 확장성을 제공한다.
위 코드처럼
DivisionOperator
MultiplicationOperator
SubtractionOperator
도 동일하게 만들어진다 .
'JAVA > 객체지향' 카테고리의 다른 글
객체지향 프로그래밍 실습(3) (1) | 2023.10.31 |
---|---|
객체지향 프로그래밍(2) (0) | 2023.10.30 |
객체지향 개념정리 (1) | 2023.10.27 |
01. 테스트코드 (0) | 2023.10.26 |
포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!