[JUnit] TDD -2

반응형

5. Refactoring

계속해서 refactoring을 진행하도록 하겠습니다.

https://en.wikipedia.org/wiki/International_Standard_Book_Number 에 따르면 ISBN Number의 로직은 아래의 code를 만족해야 합니다. 따라서 이를 참고해 checkISBN 메서드를 수정해야합니다.

😎 위키피디아의 설명에 따르면 ISBN number는 0 ~ 10 digits 사이의 number라고 되어있지만, 현재의 테스트에서는 그것을 고려하지 않습니다. 해당 내용은 또다른 테스트를 작성해 만들어야 합니다.

Wikipedia

// Returns ISBN error syndrome, zero for a valid ISBN, non-zero for an invalid one.
// digits[i] must be between 0 and 10.
int CheckISBN(int const digits[10])
{
        int i, s = 0, t = 0;

        for (i = 0; i < 10; i++) {
                t += digits[i];
                s += t;
        }

        return s % 11;
}

5-1) int -> String

먼저 ISBN number를 String으로 변경합니다.

ValidateISBN

public class ValidateISBN {

    /* int -> String 으로 변경됨 */
    public boolean checkISBN(String isbn) {
        if(isbn == "0140449116"){
            return true;
        }

        return false;
    }

}

checkValidISBN

@Test
public void checkValidISBN(){
    ValidateISBN validator = new ValidateISBN();
    boolean result = validator.checkISBN("0140449116");
    assertTrue(result);

    result = validator.checkISBN("0140177396");
    assertTrue(result);
}

여전히 test는 실패하고 있습니다.

image.png

5-2) use logic

이번에는 wiki의 logic을 참고해 checkISBN 메서드를 아래와 같이 변경합니다. 자세한 로직설명은 제외하겠습니다. TDD의 흐름을 익히는것에 집중합니다.

ValidateISBN

public class ValidateISBN {

    public boolean checkISBN(String isbn) { 
        int total = 0;

        for(int i=0; i<10; i++){
            total += isbn.charAt(i) * (10-i);
        }

        if(total % 11 ==0){
            return true;
        }else{
            return false;
        }

    }
}

이제서야 겨우 뭔가 제대로된 메서드가 완성되고 있는 것 같습니다. test 해보겠습니다.

image.png

짠! 😎 드디어 테스트가 통과했습니다.

드디어 TDD의 한 Circle을 돌았습니다. 하지만 checkISBN은 겨우 2개의 test를 통과한 것입니다. 앞으로 완벽한 메서드가 될때 까지 동일하게 1 -> 2 -> 3 순서대로 진행하면서 메서드를 수정 및 개선하면 되겠습니다.

image.png

5-3) check digits test

자 다시 처음부터 시작해봅시다. 동일하게 처음에는 fail 하는 test를 생성합니다.

이번에는 ISBN number의 digits 갯수에 대한 test를 작성해보도록 하겠습니다. 최종적으로 10 digit이 아닐 경우 NumberformatException error를 return하는지 확인하는 test를 작성할 것입니다.

먼저 아래와 같이 9 digit의 경우를 먼저 생각해보겠습니다.

@Test
public void nineDigitISBNsAreNotAllowed(){
    fail();
}

동일하게 비어있는 껍데기 테스트를 작성하고 test 해보면 당연히 실패합니다. 1단계 통과입니다.

image.png

2단계는 건너뛰고, 3단계로 넘어가 refactoring을 진행해보겠습니다.

먼저 test code를 아래와 같이 변경합니다. 이 test code에서는 input값으로 9 digit String을 사용합니다. 따라서 checkISBN 메서드가 제대로 작성되었다면 NumberFormatException을 Throw을 할 것입니다.

@Test
public void nineDigitISBNsAreNotAllowed(){
    ValidateISBN validator = new ValidateISBN();

    assertThrows(NumberFormatException.class, () -> {
        boolean result = validator.checkISBN("123456789");
    });

}

테스트해보면 테스트는 실패합니다.

실패했으니 정상인걸까요..? 😅 그렇지 않습니다. 우리는 해당 test에서 의도적으로 9 digits을 넣어 NumberFormatException이 발생하는 것을 기대했습니다. 하지만 StringIndexOutOfBoundsException을 return해 test가 실패하였습니다. 만약 NumberFormatException이 발생했다면, 이 test는 pass 되었을 겁니다.

image.png

따라서 checkISBN 메서드가 아직 제대로 작동하지않고 있음을 알 수 있습니다. 이제 checkISBN 메서드를 수정할 차례입니다.

5-4) refactoring method for check digits

checkISBN 메서드의 input String의 길이 10이 아닐 경우 NumberFormatException 을 throw 하도록 아래와 같이 수정해줍니다.

ValidateISBN

public class ValidateISBN {

    public boolean checkISBN(String isbn) {

        if(isbn.length() != 10){
            throw new  NumberFormatException("ISBN numbers must be 10 digits long");
        }

        int total = 0;

        for(int i=0; i<10; i++){
            total += isbn.charAt(i) * (10-i);
        }

        if(total % 11 ==0){
            return true;
        }else{
            return false;
        }

    }
}

테스트가 성공했습니다 🤣.

image.png

이처럼 하나의 메서드를 빈 껍데기에서 부터 시작해서 모든 상황에 대한 test를 통과할 수 있도록 작성해나가면 어느새 완벽한 메서드가 탄생하게 되는 것 입니다. 👏👏👏


참고 자료 : https://www.udemy.com/course/practical-test-driven-development-for-java-programmers/


추천서적

 

자바와 JUnit을 활용한 실용주의 단위 테스트

COUPANG

www.coupang.com

파트너스 활동을 통해 일정액의 수수료를 제공받을 수 있음


반응형

'JUnit' 카테고리의 다른 글

[JUnit] Bad Test  (0) 2020.08.20
[JUnit] Mock & Mockito -2  (0) 2020.08.20
[JUnit] Mock & Mockito -1  (0) 2020.08.20
[JUnit] Stub  (0) 2020.08.20
[JUnit] TDD -1  (0) 2020.08.17

댓글

Designed by JB FACTORY