study/JUnit

[sailor-moon] 2024.09.26_JUnit : 부분 문자열인지 확인하기

듀2 2024. 9. 26. 13:55

4. 부분 문자열인지 확인하기

 

* 코드 작성 전 테스트 조건

  1. my_string의 길이가 1 이상 100 이하인지 확인
  2. target의 길이가 1 이상 100 이하인지 확인 (통합 가능)
  3. my_string이 영소문자로만 이루어져 있는지 확인
  4. target이 영소문자로만 이루어져 있는지 확인 (통합 가능)
  5. target이 my_string의 부분 문자열이라면 1을 반환하는지 확인
  6. target이 my_string의 부분 문자열이 아니라면 0을 반환하는지 확인 (통합 가능)

* 작성 코드

package jh.day0926;

public class Substring {

    /**
     * target이 my_string의 부분 문자열인지 확인하기
     * @param my_string
     * @param target
     * @return 부분 문자열이라면 1, 아니라면 0
     */
    public int doesContainSubstring(String my_string, String target) {
        if(!checkLength(my_string, target) || !checkLowerCase(my_string, target)) {
            throw new IllegalArgumentException();
        } // end if

        int answer = 0;

        if(my_string.contains(target)) {
            answer = 1;
        } // end if

        return answer;
    } // doesContainSubstring

    /**
     * my_string과 target의 길이가 1 이상 100 이하인지 확인하기
     * @param my_string
     * @param target
     * @return true or false
     */
    public boolean checkLength(String my_string, String target) {
        return (!my_string.isBlank() && my_string.length() <= 100) &&
                (!target.isBlank() && target.length() <= 100);
    } // checkLength

    /**
     * my_string과 target이 영소문자로만 이루어져 있는지 확인하기
     * @param my_string
     * @param target
     * @return true or false
     */
    public boolean checkLowerCase(String my_string, String target) {
        char[] my_string_chars = my_string.toCharArray();
        char[] target_chars = target.toCharArray();
        boolean my_string_isLower = false;
        boolean target_isLower = false;

        for(char ch : my_string_chars) {
            if(Character.isLowerCase(ch)) {
                my_string_isLower = true;
            } // end if
        } // end for

        for(char ch : target_chars) {
            if(Character.isLowerCase(ch)) {
                target_isLower = true;
            } // end if
        } // end for

        return my_string_isLower && target_isLower;
    } // checkLowerCase

} // class

 

* 테스트 코드

package jh.day0926;

import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.CsvSource;

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

@DisplayName("부분 문자열인지 확인")
public class SubstringTest {

    private Substring substring;

    @BeforeEach
    void createInstance() {
        substring = new Substring();
    } // createInstance

    @ParameterizedTest
    @DisplayName("my_string, target의 길이 확인")
    @CsvSource(value = {"banana, ''",
            "dfjsdifjdisddfjfsijsdfkjdsklfjsdlkfjlsdkfjsdklfjdsjfsdfjdksdkfjsdklfjsdklfjsdfsdfsdfdfsdfsfddsfsfsdfs, wxyz"})
    void testLength(String my_string, String target) {
        assertThat(substring.checkLength(my_string, target)).isFalse();
    } // testLength

    @ParameterizedTest
    @DisplayName("my_string, target이 영소문자인지 확인")
    @CsvSource(value = {"BANANA, NAN", "바나나, 나나"})
    void testLowerCase(String my_string, String target) {
        assertThat(substring.checkLowerCase(my_string, target)).isFalse();
    } // testLowCase

    @ParameterizedTest
    @DisplayName("부분 문자열 확인")
    @CsvSource(value = {"banana, nan, 1", "banana, wxyz, 0"})
    void testSubstring(String my_string, String target, int expected) {
        assertThat(substring.doesContainSubstring(my_string, target)).isEqualTo(expected);
    } // testSubstring

    @ParameterizedTest
    @DisplayName("예외 처리 확인")
    @CsvSource(value = {"banana, ''", "'', nana"})
    void testException(String my_string, String target) {
        assertThatThrownBy(() -> substring.doesContainSubstring(my_string, target))
                .isInstanceOf(IllegalArgumentException.class);
    } // testException

} // class

 

* @ParameterizedTest

- 여러 개의 테스트를 한 번에 작성하기 위한 어노테이션

- Maven 사용 시 아래와 같이 dependency 주입 가능

- @ValueSource 어노테이션을 사용하여 파라미터로 테스트할 값들을 여러 개 사용할 수 있다.

- @CsvSource 어노테이션을 사용하여 파라미터로 테스트할 여러 개의 값들에 따라 결과값까지 테스트할 수 있다.

- 출처 : https://velog.io/@ohzzi/junit5-parameterizedtest

 

[JUnit5] @ParameterizedTest로 한 번에 테스트하자

테스트 코드를 짜다 보면, 한 개의 메소드에 대해서 여러 개의 테스트를 수행해야 하는 경우를 생긴다. @ParameterizedTest로 한 번에 테스트 해보자.

velog.io

 

두 개의 파라미터를 각각 테스트했는데, 함께 스터디한 멤버의 코드를 보니 파라미터끼리의 제한 조건이 같으므로 코드도 통합, 테스트도 통합할 수 있었다.
통합한 코드가 훨씬 유지보수하기 좋은 코드라고 생각했다.
제한 사항(테스트를 위한 조건)이 같다면 구현 코드도 테스트 코드도 통합할 수 있다는 점을 기억해둬야겠다.

 

영소문자 비교 시 Character Class를 복습하기 위해 for문으로 검증했는데, 정규식으로 검증하게 된다면 시간복잡도도 고려할 수 있게 된다.
영소문자만 비교하는 정규식 : ^[a-z]*$
728x90