이번에 우테코 프리코스를 하면서 테스트를 많이 접하게 되었다.
테스트는 내가 구현한 기능을 테스트하는 용도라고만 생각했는데, 잘 이용하면 학습도구로 사용될 수 있다는 것도 알게되었다!
예를 들어 특정 상황에서 Collections의 함수가 어떻게 동작하는지 눈으로 확인하기 위해 여러번 System.out을 호출할 수도 있겠지만, 여러 상황에 반복적으로 테스트하기는 번거로울 수 있다. 이 때 assertJ와 JUnit을 이용한다면 다양한 상황에서 반복적으로 테스트를 작성할 수 있기 때문에 학습 효율이 올라갈 수 있다!
물론 테스트에 대해 조금은 공부해야겠지만, 조금의 지식이 있는 사람이라면 정말 유용한 학습도구가 될 것 같다.
+) 동시에 테스트도구에도 익숙해질 수 있을 듯
이번에는 Test코드를 만들어서 Collections를 공부하는 방법에 대해 알아보겠다!
(참고: 제가 공부한 방식에 대해 작성하는 글이고, 더 좋은 방법이 있을 수 있습니다.)
테스트 하기 전..
저는 구글링이나 자바메서드를 타고 들어가서 사용법을 확인한 후 테스트하는 걸 좋아합니다!
조금의 사용법을 익힌 후, 여러 상황에 대해 테스트해보면서 확인해가는 게 저한테는 효율이 좋았습니다.
컬렉션을 테스트해보기 전 사용법에 대해 간단하게 숙지하는 걸 추천드립니다!
(어떤 역할을 하는지 알아야 테스트하는 게 의미있다고 생각해요)
테스트코드에 익숙하지 않다면 이전 글을 참고해주시거나, assertJ와 JUnit의 간단한 사용법을 알고 글을 읽으시는 걸 추천합니다!
1. String split 테스트
split은 문자열을 구분자를 기준으로 쪼개 String배열을 반환해주는 메서드이다.
사용법은 다음과 같이 구분자를 정규표현식으로 넣으면 된다
(1) 2개의 값을 쉼표기준으로 나눴을 때 동작 확인
@Test
@DisplayName("2개 값 쉼표기준 나눴을 때 결과확인")
void twoValueSplitTest() {
String testCase = "1,2";
//split이 이 상황에 잘 동작함을 알 수 있음
assertThat(testCase.split(",")).contains("2", "1");
assertThat(testCase.split(",")).containsExactly("1", "2");
}
- "1,2"값에 대해 쉼표를 기준으로 나누면 ["1", "2"] 가 나온다는 걸 알 수 있습니다
(2) 공백을 포함한 값 동작 확인
@Test
@DisplayName("공백을 포함한 값들 쉼표기준 나눴을 때 결과확인")
void splitStringIncludeBlank() {
String testCase = "1, ,3";
//split이 이 상황에 잘 동작함을 알 수 있음
assertThat(testCase.split(",")).containsExactly("1", " ", "3");
}
@Test
@DisplayName("공백을 포함한 값들 쉼표기준 나눴을 때 결과확인2")
void splitStringIncludeBlank2() {
String testCase = "1,,3";
//split이 이 상황에 잘 동작함을 알 수 있음
assertThat(testCase.split(",")).containsExactly("1", "", "3");
}
- 중간에 공백이 포함되어 있어도 잘 나누는 걸 확인할 수 있습니다
- " "든 ""든 일단 나누는 걸 볼 수 있네요
(3) 리스트에 하나만 포함되어있을 경우 동작 확인
@Test
@DisplayName("1개 값 쉼표기준으로 나눴을 때 결과확인")
void oneValueSplitTest() {
String testCase = "1";
//split이 하나의 원소만 가질 때도 잘 동작함을 알 수 있음
assertThat(testCase.split(",")).contains("1");
}
- 하나만 포함되어 있어도 잘 동작하는 걸 확인할 수 있습니다
(4) 맨 마지막에 구분자가 포함되어있는 경우
@Test
@DisplayName("맨 마지막에 쉼포가 있을 경우 결과확인")
void lastIdxIsRegex() {
String testCase = "1,";
//split이 쉼표가 마지막에 붙어있을 때는 무시한다는 걸 알 수 있음
assertThat(testCase.split(",")).contains("1");
}
- 이전에 split동작에 대해서 포스팅한 적이 있는데 그 때도 split은 마지막에 구분자가 있을 경우 무시하는 걸 유의해야한다고 했다
- 동작을 확인해보니 무시하는 걸 확인할 수 있다
(5) 맨 앞에 구분자가 포함되어있는 경우
@Test
@DisplayName("맨 앞에 쉼포가 있을 경우 결과확인")
void firstIdxIsRegex() {
String testCase = ",1";
//split이 쉼표가 앞에 붙어있을 때는 공백을 포함한다는 걸 알 수 있음
assertThat(testCase.split(",")).containsExactly("", "1");
}
- 맨 앞에 구분자가 있을 경우에는 포함하는 걸 확인할 수 있네요
2. String subString 테스트
subString은 문자열에 대한 부분문자열을 반환하는 메서드이다.
부분문자열이 시작할 인덱스에서 끝날 인덱스까지 지정해주면 해당하는 부분문자열이 반환된다
@Test
@DisplayName("subString 테스트")
void subStringTest() {
String testCase = "(1,2)";
int startIdx = 1;
int endIdx = testCase.length() - 1;
//begin 인덱스는 포함되고, end 인덱스는 포함되지 않는 걸 확인가능
assertThat(testCase.substring(startIdx, endIdx)).isEqualTo("1,2");
}
- subString의 경우 인자를 2개 받는 경우가 있다
- substring(int beginIndex, int endIndex)
- 이 경우에 beginInedx는 subString에 포함되고, endIndex는 subString에 포함되지 않는 걸 테스트를 통해 알 수 있었다
3. String charAt 테스트
charAt은 문자열에서 특정 인덱스의 char 값을 뽑아오는 메서드이다
String의 범위 내에서 사용해야 예외가 발생하지 않는다고 한다
@Test
@DisplayName("특정 위치 문자열 가져오기")
void getCharacter() {
String input = "abc";
assertThat(input.charAt(0)).isEqualTo('a');
assertThat(input.charAt(1)).isEqualTo('b');
assertThat(input.charAt(2)).isEqualTo('c');
}
- 인덱스는 0부터 시작하고, 3개의 문자열을 잘 가져온다는 걸 확인할 수 있다
@ParameterizedTest
@CsvSource(value = {"abc", "asdf", "asdfg", "asdfgh", "안녕안녕테스트", "여덟글자를테스트"})
@DisplayName("범위를 초과했을 때 예외 발생")
void rangeOverException(String testCase) {
int idx = testCase.length();
//위치 값을 벗어나면 StringIndexOutOfBoundsException이 발생하고 메시지도 다음과 같이 나오는 걸 확인가능
assertThatThrownBy(() -> testCase.charAt(idx))
.isInstanceOf(StringIndexOutOfBoundsException.class)
.hasMessageContaining("index");
}
- 문자열 범위를 초과한 값을 가져오려고 한다면 StringIndexOutOfBoundsException이 발생한다는 걸 알 수 있다
- 동시에 인덱스는 0부터 시작하여 length-1까지만 있다는 것도 알 수 있다
- 테스트를 진행하면서 새로운 사실도 알게되었다(tmi)
- 인덱스가 6이하인 경우에는 String index out of range: 6 라는 에러메시지가 뜨는데
- 인덱스가 7부터는 String index out of range: 3 이런 에러메시지가 떴다
- (왜인지는 모르겠지만 신기했다)
4. Set의 size 테스트
private Set<Integer> numbers;
@BeforeEach
void setUp() {
numbers = new HashSet<>();
numbers.add(1);
numbers.add(1);
numbers.add(2);
numbers.add(3);
}
@Test
@DisplayName("크기 테스트")
void setSizeTest() {
assertThat(numbers.size()).isEqualTo(3);
}
- BeforeEach로 numbers라는 집합에 1,1,2,3을 넣었다
- 집합은 중복을 허용하지 않기 때문에 1,2,3이 들어갔다는 걸 예상할 수 있다
- 크기를 테스트해보면 역시 크기는 3임을 알 수 있다
5. Set의 contains 테스트
cotains 메서드는 set에 어떤 Object가 포함되어있는지 확인하여 boolean 값을 반환한다
private Set<Integer> numbers;
@BeforeEach
void setUp() {
numbers = new HashSet<>();
numbers.add(1);
numbers.add(1);
numbers.add(2);
numbers.add(3);
}
@ParameterizedTest
@CsvSource(value = {"1", "2", "3"})
@DisplayName("contains 포함하고 있는지 반환여부 확인")
void contains_ShouldReturnTrueForIncludingElement(int number) {
assertThat(numbers.contains(number)).isTrue();
}
- 값을 잘 포함하고 있는지 테스트한다
- 1,2,3은 set에 포함되어 있는 값이기 때문에 contains의 결과는 true가 나올 것이다
- 확인해보면 잘 동작한다
@ParameterizedTest
@CsvSource(value = {"1:true", "2:true", "3:true", "4:false", "5:false"}, delimiter = ':')
@DisplayName("contains메소드 테스트2")
void contains_ShouldReturnTrueOrFalseForElement(int number, boolean isTrue) {
assertThat(numbers.contains(number)).isEqualTo(isTrue);
}
- 포함되지 않는 값들은 false를 반환하는지 확인한다
- 1,2,3의 경우 포함되기 때문에 true를 반환하고, 4,5의 경우 포함되지 않기 때문에 false를 반환한다
- 테스트가 잘 동작함을 확인할 수 있다
테스트를 학습도구로 사용하는 새로운 관점에 대해 알아봤는데, 확실히 다양한 상황에 대해 테스트를 작성해보면 메서드의 동작에 대해 더 잘 알게 될 것 같다. 다음에는 다른 Collections에 대해서도 테스트를 작성해보면서 학습해봐야겠다
'프로그래밍 언어 > Java' 카테고리의 다른 글
IntelliJ java.util.concurrent.TimeUnit 이 없다고 나오는 에러(JDK21) (3) | 2024.10.26 |
---|---|
[JAVA] 자주 사용하는 Exception들 알아보기(IllegalArgumentException, IllegalStateException, IOException, NullPointerException) (0) | 2023.11.08 |
[JAVA] 상수와 enum 공부하기2 (0) | 2023.11.07 |
[JAVA] 상수와 enum 공부하기1 (0) | 2023.11.07 |
[JAVA] 상수를 private static final로 선언하는 이유 (0) | 2023.11.07 |