컴퓨터공부/Kotlin & Java

TDD 교육(실습) 정리

achivenKakao 2017. 9. 15. 02:31

TDD교육을 받은지 좀 됐는데... 미루다 이제야 정리를 한다.

첨부의 자료를 참고하면 Junit 테스트 방법을 알 수 있다. 내가 별로 추가해야할 건 없어 보인다.


다만 그 전에 이해해야 하는 TDD Cycle를 알고 가면 좋을 것 같다.





1. 시작은..  test가  실패할 case를 먼저 작성하는 것이다.

   1. 이건... 정상적은 class에서는 성공했을 case이지만 현재 구현에서는 fail이 될 case를 작성하라는 것이다. 즉, 정상적인 TC작성이다.

      ex) 


public class FizzBuzzTest {

// Arrange - Given

Fizz fizzBuzz = new Fizz();

@Test

public void fizz_should_say_number_for_1() {

// // Arrange - Given

// Fizz fizzBuzz = new Fizz();

// Act - When

String result = fizzBuzz.say(1);

// Assert - Then

assertEquals("1", fizzBuzz.say(1));

}

}



2. 그리고 실패한 case를 성공 시키도록 class를 수정한다.

    1. class 구현은 simple하고 fast해야 한다. 

    2. 처음에는 class 구현 시 가짜 구현을 도입해라. Harding coding으로 구현하라는 뜻이다... 

    3. 즉, 첫 testcase가 간신히 success가 되도록 엉망(?)으로 구현하라는 뜻이다.


3. 새로운 논리를 찾아서 refactoring 해라..

    1. 처음에 class를 Harding coding 했다면 스스로가 빡쳐서 올바른 class를 작성하고 싶을 것이다. 

    2. 그럼 이제 다시, 1번에서 한것과 같이 실패할 case를 찾아서 TC로 작성하고 1 ~ 3번을 반복해라. 

    3. 더 이상 실패할 case를 못 찾는다면 TC를 더 추가할 필요 없다. 즉 이게 완료조건이다.



TC는 FizzBuzzTest 위 예제와 같이 Arrange, Act, Assert로 구성을 하고 작성한다. 보통 Arrange는 위와같이 독립적으로 옮길 수 있으며, 다른 test 함수를 작성하더라도 독립적인 코드처럼 각 함수를 위해서 한번씩 실행된다.



 import static org.junit.Assert.*;


import org.junit.Test;


public class FizzBuzzTest {

// Arrange - Given

Fizz fizzBuzz = new Fizz();

@Test

public void fizz_should_say_number_for_2() {

// Act - When

String result = fizzBuzz.say(2);


// Assert - Then

assertEquals("2", fizzBuzz.say(2));

}


@Test

public void fizz_should_say_number_for_3의배수_5의배수가_아닌_경우() {

assertEquals("1", fizzBuzz.say(1));

assertEquals("2", fizzBuzz.say(2));

}


@Test

public void fizz_should_say_Buzz_for_multiples_of_15() {

assertEquals("FizzBuzz", fizzBuzz.say(15));

assertEquals("FizzBuzz", fizzBuzz.say(30));

}


@Test

public void fizz_should_say_Buzz_for_multiples_of_5() {

assertEquals("Buzz", fizzBuzz.say(5));

assertEquals("Buzz", fizzBuzz.say(10));

}


@Test

public void fizz_should_say_Buzz_for_multiples_of_3() {

assertEquals("Fizz", fizzBuzz.say(3));

assertEquals("Fizz", fizzBuzz.say(6));

}

}



public class Fizz {

//      첫 구현 fizz_should_say_number_for_2()를 간신히 통과 시킬 수준

// public String say(int number) {

// if( number == 2)

// return "" + number;

// return "" + number;

// }


// 두 번째 구현 : fizz_should_say_number_for_3의배수_5의배수가_아닌_경우() 를 통과 시킬 수준 및 완성본

public String say(int number) {

if(number %15 == 0) {

return "FizzBuzz";

}

if(number %3 == 0) {

return "Fizz";

}

if(number %5 == 0) {

return "Buzz";

}

return String.valueOf(number);

}

} 




TDD cycle 1. 




TDD cycle 2. 




내가 필기한 TDD cycle 3.







+


출처 : http://www.nextree.co.kr/p11104/



이번 글에서는 JUnit 단위 테스트 Framework에 대해 알아봅니다. JUnit은 Java의 단위 테스트에서 빼놓고 이야기하기 어려울 정도로 절대적인 위치를 차지하고 있습니다. 그래서 높은 수준은 아니어도 기본적인 내용은 누구나 알고 있어야 합니다. 이번 글에서는 Eclipse에서 JUnit을 설치하는 방법과 간단한 예제를 통해 JUnit 사용법을 알아봅니다.

1. JUnit이란?

JUnit은 단위 테스트 도구입니다. 외부 테스트 프로그램(케이스)을 작성하여 System.out으로 번거롭게 디버깅하지 않아도 됩니다. 프로그램 테스트 시 걸릴 시간도 관리할 수 있게 해주며 오픈 소스이며, 플러그인 형태로 Eclipse에 포함되어 있습니다. 하나의 jar 파일이 전부이며 사용법도 간단합니다. 어느 정도 개발이 진행되면 프로그램에 대한 단위 테스트는 반드시 수행해야 합니다. JUnit은 보이지 않고 숨겨진 단위 테스트를 끌어내어 정형화시켜 단위 테스트를 쉽게 해주는 테스트용 Framework 입니다. JDK 1.4에서 추가된 assertXXX를 사용하여 Test를 진행합니다. JUnit은 테스트 결과를 확인하는 것 이외 최적화된 코드를 유추해내는 기능도 제공합니다. 또한, 테스트 결과를 단순한 텍스트로 남기는 것이 아니라 Test클래스로 남깁니다. 그래서 개발자에게 테스트 방법 및 클래스의 History를 넘겨줄 수도 있습니다.

2. 특징

  • 단위 테스트 Framework 중 하나
  • 문자 혹은 GUI 기반으로 실행됨
  • 단정문으로 테스트 케이스의 수행 결과를 판별함(assertEquals(예상 값, 실제 값))
  • 어노테이션으로 간결하게 지원함
  • 결과는 성공(녹색), 실패(붉은색) 중 하나로 표시

3. Eclipse에 JUnit 설정하기

  • Java Project를 생성
  • Project 이름에서 오른쪽 마우스를 클릭하고 Properties를 선택
  • Java BuildPath를 선택
  • Libraries 탭을 선택하고, Add Library를 선택

< 그림 1 >

JUnit을 선택하고, Next 버튼 선택

< 그림 2 >

버전을 선택하고, Finish 버튼 선택

< 그림 3 >

JUnit이 추가 된 사항을 확인 할 수 있습니다.

< 그림 4 >

그림 4까지 하셨으면 Eclipse에 JUnit이 설정되었습니다. 지금부터는 간단한 Calculator 클래스를 통해 Eclipse에서 어떻게 JUnit을 사용하는지 알아봅니다.

4. JUnit 사용하기

먼저 com.calculator 패키지를 만들고 Calculator 클래스를 만듭니다. 메소드는 int형 두 개의 파라미터를 받아 두 개의 합을 리턴 하는 간단한 sum 메소드 입니다. 소스는 다음과 같습니다.

package com.calculator;

public class Calculator {  
    public int sum(int num1, int num2){
        return num1 + num2;
    }
}

Calculator 클래스를 테스트하기 위한 테스트 클래스를 만들겠습니다. 먼저 com. Calculator.test 패키지를 만듭니다. 그리고 com. Calculator.test 패키지에서 마우스 오른쪽 버튼 -> New -> JUnit Test Case 선택

< 그림 5 >

아래 그림에서

①은 테스트 클래스 이름 입력 부분이고, 테스트 클래스 이름은 테스트할 클래스 이름에 Test를 추가해서 입력합니다.

②는 테스트 클래스가 테스트하게 될 클래스를 지정하는 부분입니다.

Next 버튼 선택,

< 그림 6 >

Calculator 클래스에서 테스트할 메소드를 선택하고 Finish 버튼을 선택,

< 그림 7 >

다음과 같은 테스트 코드가 생성됩니다.

package com.calculator.test;  
import static org.junit.Assert.*;  
import org.junit.Test;  
public class CalculatorTest {  
    @Test
    public void testSum() {
        fail("Not yet implemented");
    }
}

위 testSum 메소드를 보면 어노테이션으로 @Test가 선언된 것을 볼 수 있습니다. 이 의미는 testSum 메소드가 단위 테스트 메소드임을 지정한다는 것입니다. 그리고 이 testSum 메소드 안에서 Calculator 클래스의 Sum메소드를 테스트합니다.

testSum 메소드를 다음과 같이 수정하였습니다.

    @Test
    public void testSum() {
        Calculator calculator = new Calculator();
        assertEquals(30, calculator.sum(10, 20));
    }

위 소스를 보시면 Calculator 클래스 객체를 생성한 후 assertEquals 메소드를 사용하여 sum 메소드의 리턴 값이 제대로 반환되는지 확인합니다. 반환 값이 지정한 결과와 같으면 테스트는 성공입니다. 하지만 반환 값이 생각한 결과와 같지 않으면 실패입니다.

테스트 클래스를 실행하는 방법은 테스트 클래스에서 마우스 오른쪽 버튼 -> RunAs -> JUnit Test를 선택

< 그림 8 >

테스트 메소드가 아무런 문제 없이 성공되면 그림 9와 같습니다.

< 그림 9 >

테스트 메소드에 문제가 있어 실패하면 그림 10과 같습니다.

< 그림 10 >

지금까지 간단한 Calculator 클래스를 통해 JUnit에 대해 알아보았습니다. 예제 소스에서 assertEquals 메소드를 보셨을 겁니다. 이 메소드는 JUnit에서 가장 많이 사용되는 메소드입니다. 이외에도 유용한 메소드가 있으며 이러한 메소드를 단정문 이라고도 합니다. 단정문에 해당하는 메소드는 많이 있으며 대표적인 것에 대해 알아보겠습니다.

5. 대표적인 단정문

assertArrayEquals(a,b) : 배열 a와b가 일치함을 확인 
assertEquals(a,b) : 객체 a와b의 값이 같은지 확인 
assertSame(a,b) : 객체 a와b가 같은 객체임을 확인 
assertTrue(a) : a가 참인지 확인 
assertNotNull(a) : a객체가 null이 아님을 확인 
이외에도 다양한 단정문이 존재합니다. 자세한 내용은 아래 링크를 가시면 확인하실 수 있습니다.http://junit.sourceforge.net/javadoc/org/junit/Assert.html

6. 어노테이션 활용하기

Java 언어 자체가 좀 더 넓게 확장하고 다양하게 발전할 수 있도록 도와준 어노테이션을 JUnit에서 활용할 수 있습니다.

(1) 테스트 메소드 지정하기

@Test가 메소드 위에 선언되면 이 메소드는 테스트 대상 메소드임을 의미합니다.

    @Test
    public void testSum() { 

    }

(2) 테스트 메소드 수행시간 제한하기

@Test(timeout=5000)를 메소드 위에 선언합니다. 시간단위는 밀리 초 입니다. 이 테스트 메소드가 결과를 반환하는데 5,000밀리 초를 넘긴다면 이 테스트는 실패입니다.

    @Test(timeout=5000)
    public void testSum() { 

    }

(3) 테스트 메소드 Exception 지정하기

@Test(expected=RuntimeException.class)가 메소드 위에 선언되면 이 테스트 메소드는 RuntimeException이 발생해야 테스트가 성공, 그렇지 않으면 실패입니다.

    @Test(expected=RuntimeException.class)
    public void testSum() { 

    }

(4) 초기화 및 해제

@BeforeClass, @AfterClass가 메소드 위에 선언되면 해당 테스트 클래스에서 딱 한 번씩만 수행되도록 지정하는 어노테이션 입니다.

    @BeforeClass
    public static void setUpBeforeClass() throws Exception {

    }

    @AfterClass
    public static void tearDownAfterClass() throws Exception {

    }

@Before, @After가 메소드 위에 선언되면 해당 테스트 클래스 안에 메소드들이 테스트 되기 전과 후에 각각 실행되게 지정하는 어노테이션 입니다.

    @Before
    public void setUp() throws Exception {

    }

    @After
    public void tearDown() throws Exception {

    }

아래 그림과 같이 표현할 수 있습니다.

< 그림 11 >

@BeforeClass 어노테이션은 테스트 클래스 수행 시 단위 테스트 메소드 보다 먼저 딱 한 번 수행되어야 할 경우 지정합니다. 예를 들어 DB 연결 시 드라이버 로딩 부분을 @BeforeClass로 지정한 메소드에 작성합니다. 반대로 @AfterClass 어노테이션은 단위 테스트 함수들이 다 수행되고 맨 마지막에 수행되어야 할 경우 지정합니다. 예를 들어 DB 연결 후 마지막에 드라이버를 반납하는 부분을 @AfterClass로 지정한 메소드에 작성합니다.

@Before와@After는 @Test로 지정된 단위 테스트 메소드가 실행되기 전 한 번씩 수행하거나 실행되고 난 후 수행되어야 하는 부분을 작성합니다. 예를 들어 공통으로 객체를 생성하는 코드를 @Test로 지정된 단위 테스트 메소드 안에 있다면 그 부분을 @Before에 지정된 메소드에 작성합니다.

7. 마치며...

지금까지 단위 테스트 Framework인 JUnit에 대해 알아보았습니다. JUnit을 사용하여 테스트 클래스를 작성하는 데 있어 깊은 내용은 아니지만, Eclipse에서 설치 방법과 어떻게 사용하는지를 살펴 보았습니다. JUnit을 처음 접하시는 분들께 작은 도움이나마 되었으면 하는 바램입니다.

감사합니다.

참고 도서 및 사이트