JUnit로 검색한 결과 :: 시소커뮤니티[SSISO Community]
 
SSISO 카페 SSISO Source SSISO 구직 SSISO 쇼핑몰 SSISO 맛집
추천검색어 : JUnit   Log4j   ajax   spring   struts   struts-config.xml   Synchronized   책정보   Ajax 마스터하기   우측부분

회원가입 I 비밀번호 찾기


SSISO Community검색
SSISO Community메뉴
[카페목록보기]
[블로그등록하기]  
[블로그리스트]  
SSISO Community카페
블로그 카테고리
정치 경제
문화 칼럼
비디오게임 스포츠
핫이슈 TV
포토 온라인게임
PC게임 에뮬게임
라이프 사람들
유머 만화애니
방송 1
1 1
1 1
1 1
1 1
1

JUnit로 검색한 결과
등록일:2008-04-23 15:47:56
작성자:
제목:JUnit 4로 뛰어들기


자바 5 주석을 사용한 효율적인 테스트


난이도 : 중급

Andrew Glover, President, Stelligent Incorporated

2007 년 4 월 10 일

JUnit 4에서는 자바(Java™) 5 주석(annotation)의 효율적인 유연성을 위해 기존의 엄격한 명명 규칙 및 상속 계층 구조를 없앴다. 테스트 전문가로 활동하고 있는 Andrew Glover는 본 튜토리얼에서 코드 품질과 관련하여 자신이 연재한 인기 있는 기술문서의 내용을 보충하는 시간을 마련하여 매개변수 테스트, 예외 테스트, 제한 시간 테스트 등 주석을 통해 새로운 기능을 활용하는 방법에 대해 설명한다. 또한 JUnit 4의 유연한 픽스쳐(fixture)에 대해 소개하고 스위트(suite) 대신 주석을 사용하여 테스트를 실행하기 전에 논리적으로 그룹화하는 방법에 대해서도 설명한다. 본 튜토리얼에는 이클립스(Eclipse)에서 실행되는 일부 샘플 테스트와 호환되지 않는 이전 버전의 앤트(Ant)에서 JUnit 4 테스트를 실행하기 위한 지침이 포함되어 있다.

시작하기 전에

튜토리얼 소개

자 바 5 주석은 JUnit에 커다란 변화를 가져왔으며 많은 테스트 프레임워크 개발자에게 효율적인 작업 방식으로 점차 인식되고 있지만 이들에게 익숙한 기술은 아니다. 본 튜토리얼에서는 JUnit 4의 가장 중요한 변경 사항에 대해 설명하고 독자가 이미 들어보았을지도 모르지만 아직 사용하고 있지는 않을 흥미로운 새 기능들에 대해 설명한다.




위로


목적

본 튜토리얼에서는 JUnit 4의 기본 개념에 대해 단계별로 설명하고 특히 새로운 자바 5 주석 기능에 대해 자세히 다룬다. 한 시간 분량의 본 튜토리얼 학습을 마치면 JUnit 4의 주요 변경 사항에 대해 이해할 수 있을 뿐만 아니라 예외 테스트, 매개변수 테스트 및 유연한 새 픽스쳐 모델과 같은 기능에 대해 알게 된다. 또한 테스트를 선언하는 방법, 스위트 대신 주석을 사용하여 테스트를 실행하기 전에 논리적으로 그룹화하는 방법, 명령행뿐만 아니라 이클립스 3.2 또는 앤트에서 테스트를 실행하는 방법에 대해서도 설명한다.




위로


필요한 사전 지식

본 튜토리얼을 최대한 활용하기 위해서는 일반적인 자바 개발에 익숙해야 한다. 본 튜토리얼에서는 또한 독자가 개발자 테스트의 중요성을 이해하고 있으며 기본 패턴 매칭에 익숙하다고 가정한다. JUnit 4 테스트 실행 섹션의 내용을 테스트하기 위해서는 이클립스 3.2를 IDE로 사용하고 앤트 1.6 이상을 사용해야 한다. 이전 버전의 JUnit에 익숙하지 않더라도 본 튜토리얼을 이해하는 데에는 문제가 없다.




위로


시스템 요구 사항

본 튜토리얼의 코드를 시험해보려면 썬의 JDK 1.5.0_09 이상 또는 자바 기술 1.5.0 SR3용 IBM 개발자 킷이 설치된 시스템이 필요하다. 이클립스에서 JUnit 4 실행 섹션의 경우 이클립스 3.2 이상이 설치된 시스템이 필요하다. 앤트 섹션의 경우 버전 1.6 이상이 필요하다.

본 튜토리얼에서 권장하는 시스템 구성은 다음과 같다.

  • 기본 메모리가 최소 500MB 이상이고 썬 JDK 1.5.0_09 이상 또는 자바 기술 1.5.0 SR3용 IBM 개발자 킷을 지원하는 시스템
  • 소프트웨어 컴포넌트 및 예제를 설치하기 위한 최소 20MB 이상의 하드 디스크 여유 공간

본 튜토리얼의 지침은 마이크로소프트 윈도우 운영 체제를 기반으로 한다. 또한 본 튜토리얼에서 다루는 모든 도구는 리눅스와 유닉스 시스템에서도 작동한다.


--다음페이지--

JUnit 4의 새로운 기능

자바 5 주석 덕분에 JUnit 4가 이전보다 더욱 가벼워졌고 유연해졌다. 일부 흥미로운 새 기능을 위해 이전의 엄격한 명명 규칙과 상속 계층 구조가 사라졌다. 다음은 JUnit 4의 새로운 기능을 간략히 설명해 놓은 목록이다.

  • 매개변수 테스트
  • 예외 테스트
  • 제한 시간 테스트
  • 유연한 픽스쳐
  • 테스트를 쉽게 무시하는 방법
  • 테스트를 논리적으로 그룹화하는 방법

이러한 기능과 더 많은 새로운 기능을 이후 섹션에서 설명하기에 앞서 JUnit 4의 가장 중요한 변경 사항에 대해 설명하겠다.

기존 버전의 문제

JUnit 4에 자바 5 주석 기능이 추가되기 전에 이 프레임워크에는 기능을 사용하는 데 반드시 필요한 두 가지 규칙이 존재했다. 첫 번째는 JUnit에서 논리적 테스트로 작동하도록 작성된 모든 메서드는 test라는 단어로 반드시 시작해야 한다는 것이다. testUserCreate와 같이 이 단어로 시작하는 모든 메서드는 테스트 메서드 이전 및 이후에 픽스쳐 실행을 보장하는 잘 정의된 테스트 프로세스에 따라 실행되었다. 두 번째 규칙은 JUnit에서 테스트를 포함하는 클래스 객체를 인식하기 위해 클래스 자체가 JUnitTestCase에서 확장되어야 한다는 점이다(또는 일부 파생). 이러한 두 가지 규칙을 위반하는 테스트는 실행할 수 없었다.

Listing 1은 JUnit 4 이전에 작성된 JUnit 테스트를 보여준다.


Listing 1. 이렇게 어렵게 작성해야 할 필요가 있을까?
                    
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import JUnit.framework.TestCase;

public class RegularExpressionTest extends TestCase {

private String zipRegEx = "^\\d{5}([\\-]\\d{4})?$";
private Pattern pattern;

protected void setUp() throws Exception {
this.pattern = Pattern.compile(this.zipRegEx);
}

public void testZipCode() throws Exception{
Matcher mtcher = this.pattern.matcher("22101");
boolean isValid = mtcher.matches();
assertTrue("Pattern did not validate zip code", isValid);
}
}

많은 사람들이 JUnit 4에서 주석이 사용된 것은 .NET의 NUnit과 TestNG의 영향을 받은 것이라고 말한다. 다른 테스트 프레임워크에서의 주석에 대한 자세한 내용은 참고자료를 참조하기 바란다.

새로운 버전의 이점

자바 5 주석을 사용할 수 있는 JUnit 4에서는 이러한 규칙이 모두 사라졌다. 클래스 계층 구조는 더 이상 필요하지 않으며 테스트로 작동할 메서드도 새롭게 정의된 @Test 주석으로만 기술하면 된다.

Listing 2는 Listing 1에 표시된 것과 동일한 테스트를 보여주지만 주석을 사용하여 다시 정의되어 있다.


Listing 2. 주석을 사용한 테스트
                    
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.JUnit.BeforeClass;
import org.JUnit.Test;
import static org.JUnit.Assert.assertTrue;

public class RegularExpressionTest {
private static String zipRegEx = "^\\d{5}([\\-]\\d{4})?$";
private static Pattern pattern;

@BeforeClass
public static void setUpBeforeClass() throws Exception {
pattern = Pattern.compile(zipRegEx);
}

@Test
public void verifyGoodZipCode() throws Exception{
Matcher mtcher = this.pattern.matcher("22101");
boolean isValid = mtcher.matches();
assertTrue("Pattern did not validate zip code", isValid);
}
}

Listing 2에서 언급한 테스트는 코드로 작성하기가 더 쉽지 않을 수도 있지만 확실한 것은 더 쉽게 이해할 수 있다는 것이다.




위로


간단한 문서화

주석이 갖는 한 가지 유용한 점은 프레임워크의 내부 모델에 대한 자세한 이해 없이도 각 메서드의 사용 의도를 명확하게 문서화한다는 점이다. @Test로 테스트 메서드를 표시하는 것 이상으로 더 명확한 방법이 있을까? 이는 각 메서드가 전반적인 테스트 케이스에서 어떤 역할을 담당하는지만 이해하고 싶어도 JUnit 규칙에 대한 상당한 이해가 필요했던 기존 JUnit 스타일에 비해 크게 향상된 점이다.

이미 작성된 테스트를 파싱할 때에도 주석은 큰 도움이 되지만 테스트 작성 중에 추가 작업이 발생할 경우에는 더욱 필수적인 요소가 된다.


--다음페이지--

주석을 사용한 테스트

자바 5 주석으로 인해 JUnit 4는 이전 버전과는 크게 다른 프레임워크가 되었다. 이 섹션에서는 테스트 선언과 예외 테스트 같은 핵심 영역뿐만 아니라 제한 시간 테스트 영역에서 주석을 사용하는 방법과 원치 않는 또는 사용할 수 없는 테스트를 무시하는 방법에 대해 설명한다.

테스트 선언

JUnit 4에서 테스트를 선언하기 위해서는 단순히 테스트 메서드에 @Test 주석만 덧붙이면 된다. Listing 3에서와 같이 특정 클래스에서 확장할 필요가 없다.


Listing 3. JUnit 4에서 테스트 선언
                    
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.JUnit.BeforeClass;
import org.JUnit.Test;
import static org.JUnit.Assert.assertFalse;

public class RegularExpressionTest {
private static String zipRegEx = "^\\d{5}([\\-]\\d{4})?$";
private static Pattern pattern;

@BeforeClass
public static void setUpBeforeClass() throws Exception {
pattern = Pattern.compile(zipRegEx);
}

@Test
public void verifyZipCodeNoMatch() throws Exception{
Matcher mtcher = this.pattern.matcher("2211");
boolean notValid = mtcher.matches();
assertFalse("Pattern did validate zip code", notValid);
}
}

정적 가져오기에 대해 알아야 할 것

필자는 Listing 3에서 Assert 클래스의 assertFalse() 메서드를 가져오기 위해 자바 5의 정적 가져오기 기능을 사용했다. 이는 테스트 클래스가 이전 버전의 JUnit에서와 같이 TestCase에서 확장되지 않기 때문이다.




위로


예외 테스트

이전 버전의 JUnit에서와 같이 일반적으로 테스트가 Exception을 throw하는 경우를 지정하는 것이 좋다. 이 규칙을 무시해야 하는 유일한 경우는 특정 예외에 대한 테스트를 시도하려는 경우다. 테스트가 예외를 throw하면 프레임워크가 실패를 보고한다.

특정 예외에 대한 테스트를 수행하고자 할 때 JUnit 4의 @Test 주석은 테스트가 예외시 throw해야 하는 예외 유형을 나타내는 expected 매개변수를 지원한다.

간단한 비교로 새로운 매개변수의 차이점을 이해할 수 있다.

JUnit 3.8에서 예외 테스트

testZipCodeGroupException()으로 명명된 Listing 4의 JUnit 3.8 테스트는 선언한 정규식의 세 번째 그룹을 얻으려고 시도할 경우 IndexOutOfBoundsException이 발생하는 것으로 확인된다.


Listing 4. JUnit 3.8에서 예외 테스트
                    
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import JUnit.framework.TestCase;

public class RegularExpressionTest extends TestCase {

private String zipRegEx = "^\\d{5}([\\-]\\d{4})?$";
private Pattern pattern;

protected void setUp() throws Exception {
this.pattern = Pattern.compile(this.zipRegEx);
}

public void testZipCodeGroupException() throws Exception{
Matcher mtcher = this.pattern.matcher("22101-5051");
boolean isValid = mtcher.matches();
try{
mtcher.group(2);
fail("No exception was thrown");
}catch(IndexOutOfBoundsException e){
}
}
}

이전 버전의 JUnit에서는 try/catch를 작성하여 예외가 발생하지 않으면 실패하는 이러한 간단한 테스트를 위해서도 상당히 많은 양의 코드를 작성해야 한다.

JUnit 4에서 예외 테스트

Listing 5의 예외 테스트는 Listing 4와 동일하지만 새로운 expected 매개변수를 사용한다는 점이 다르다(Listing 4에서 @Test 주석에 IndexOutOfBoundsException 예외를 전달하여 테스트를 수정할 수 있었다).


Listing 5. 'expected' 매개변수를 사용한 예외 테스트
                    
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.JUnit.BeforeClass;
import org.JUnit.Test;

public class RegularExpressionJUnit4Test {
private static String zipRegEx = "^\\d{5}([\\-]\\d{4})?$";
private static Pattern pattern;

@BeforeClass
public static void setUpBeforeClass() throws Exception {
pattern = Pattern.compile(zipRegEx);
}

@Test(expected=IndexOutOfBoundsException.class)
public void verifyZipCodeGroupException() throws Exception{
Matcher mtcher = this.pattern.matcher("22101-5051");
boolean isValid = mtcher.matches();
mtcher.group(2);
}
}




위로


제한 시간 테스트

JUnit 4의 테스트 케이스에서는 제한 시간 값을 매개변수로 사용할 수 있다. Listing 6에서와 같이 timeout 값은 테스트가 실행하는 데 걸리는 최대 시간을 나타낸다. 시간이 초과되면 테스트가 실패한다.


Listing 6. timeout 값을 사용한 테스트
                    
@Test(timeout=1)
public void verifyFastZipCodeMatch() throws Exception{
Pattern pattern = Pattern.compile("^\\d{5}([\\-]\\d{4})?$");
Matcher mtcher = pattern.matcher("22011");
boolean isValid = mtcher.matches();
assertTrue("Pattern did not validate zip code", isValid);
}

제한 시간을 사용한 테스트는 쉽게 작성할 수 있다. 메서드에서 단순히 @Test 다음에 timeout 값을 삽입하면 자동화된 제한 시간 테스트를 구현할 수 있다.




위로


테스트 무시

JUnit 4 버전이 나오기 전에는 깨져 있거나 불완전한 테스트를 무시하기가 어려웠다. 프레임워크에서 특정 테스트를 무시하도록 하려면 테스트 명칭을 따르지 않도록 테스트 이름을 바꾸어야 했다. 예를 들어 필자도 테스트가 실행되지 않도록 표시하기 위해 테스트 메서드 앞에 "_"를 붙이는 습관이 있었다.

JUnit 4에서는 @Ignore를 붙인 주석을 통해 프레임워크에서 특정 테스트 메서드를 무시하도록 할 수 있다. 또한 다른 개발자가 무시된 테스트를 이상하게 여기지 않도록 메시지 설명을 전달할 수도 있다.

@Ignore 주석

Listing 7은 정규식이 아직 작동하지 않는 테스트를 쉽게 무시하는 방법을 보여준다.


Listing 7. 테스트 무시
                    
@Ignore("this regular expression isn't working yet")
@Test
public void verifyZipCodeMatch() throws Exception{
Pattern pattern = Pattern.compile("^\\d{5}([\\-]\\d{4})");
Matcher mtcher = pattern.matcher("22011");
boolean isValid = mtcher.matches();
assertTrue("Pattern did not validate zip code", isValid);
}

테스트 무시에 대한 알림 메시지

예를 들어 이클립스에서 이 테스트를 실행하면 그림 1과 같이 테스트가 무시되었다는 알림이 보고된다.


Figure 1. 그림 1. 무시된 테스트가 이클립스에서 표시되는 모습
무시한 테스트는 이클립스에서 문서화된다


--다음페이지--

테스트 픽스쳐

테스트 픽스쳐는 JUnit 4의 새로운 기능은 아니지만 픽스쳐 모델이 새롭게 향상되었다. 이 섹션에서는 픽스쳐를 사용하는 이유와 경우에 대해 설명하고 이전 버전의 유연하지 않은 픽스쳐와 JUnit 4의 새로운 모델 간의 차이점을 설명한다.

픽스쳐를 사용하는 이유

픽 스쳐는 특정 로직이 테스트 전후에 실행되도록 보장하는 하나의 약정이므로 손쉽게 재활용할 수 있다. 이전 버전의 JUnit에서 이 약정은 픽스쳐를 구현했는지 여부에 관계없이 적용되었다. 하지만 JUnit 4에서 픽스쳐는 주석을 통해 명시적으로 변경되므로 사용자가 픽스쳐를 사용하도록 결정한 경우에만 약정이 적용된다.

테스트 전후에 픽스쳐를 실행할 수 있도록 보장하는 약정을 통해 재사용이 가능한 로직을 코딩할 수 있다. 예를 들어 이러한 로직은 여러 테스트 케이스 또는 로직에서 데이터 종속 테스트를 실행하기 전에 데이터베이스를 채우도록 테스트를 수행할 클래스를 초기화할 수 있다. 이러한 테스트 케이스는 공통 로직을 사용하므로 어느 쪽이든 픽스쳐를 사용하면 테스트 케이스를 더 쉽게 관리할 수 있다.

픽스쳐는 동일한 로직을 사용하는 여러 테스트를 실행 중이고 이들 중 일부 또는 전체가 실패할 경우에 특히 유용하다. 각 테스트의 설정 로직에서 실패 원인을 확인하는 대신 한 곳에서 실패 원인을 추론할 수 있다. 또한 테스트가 일부만 성공하고 일부는 실패하는 경우 이러한 실패의 공통 원인으로 픽스쳐 로직을 검사하지 않아도 된다.




위로


유연하지 않은 픽스쳐

O이전 버전의 JUnit에서는 다소 유연하지 않은 픽스쳐 모델이 사용되었다. 여기에서는 setUp()tearDown() 메서드를 사용하여 모든 테스트 메서드를 래핑해야 했다. Listing 8에서는 이러한 모델의 잠재적인 단점을 확인할 수 있다. 여기에서는 setUp() 메서드가 구현되며 따라서 정의된 각 테스트에 대해 한 번씩 두 번 실행된다.


Listing 8. 유연하지 않은 픽스쳐
                    
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import JUnit.framework.TestCase;

public class RegularExpressionTest extends TestCase {

private String zipRegEx = "^\\d{5}([\\-]\\d{4})?$";
private Pattern pattern;

protected void setUp() throws Exception {
this.pattern = Pattern.compile(this.zipRegEx);
}

public void testZipCodeGroup() throws Exception{
Matcher mtcher = this.pattern.matcher("22101-5051");
boolean isValid = mtcher.matches();
assertEquals("group(1) didn't equal -5051", "-5051", mtcher.group(1));
}

public void testZipCodeGroupException() throws Exception{
Matcher mtcher = this.pattern.matcher("22101-5051");
boolean isValid = mtcher.matches();
try{
mtcher.group(2);
fail("No exception was thrown");
}catch(IndexOutOfBoundsException e){
}
}
}




위로


해결 방법

이전 버전의 JUnit에서는 TestSetup 데코레이터를 사용하여 픽스쳐가 한 번만 실행되도록 지정할 수 있었지만 Listing 9와 같이 이러한 방식은 번거로운 작업이다(필수 suite() 메서드 참조):


Listing 9. JUnit 4 이전의 TestSetup
                    
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import JUnit.extensions.TestSetup;
import JUnit.framework.Test;
import JUnit.framework.TestCase;
import JUnit.framework.TestSuite;
import JUnit.textui.TestRunner;

public class OneTimeRegularExpressionTest extends TestCase {

private static String zipRegEx = "^\\d{5}([\\-]\\d{4})?$";
private static Pattern pattern;

public static Test suite() {
TestSetup setup = new TestSetup(
new TestSuite(OneTimeRegularExpressionTest.class)) {
protected void setUp() throws Exception {
pattern = Pattern.compile(zipRegEx);
}
};
return setup;
}

public void testZipCodeGroup() throws Exception {
Matcher mtcher = pattern.matcher("22101-5051");
boolean isValid = mtcher.matches();
assertEquals("group(1) didn't equal -5051", "-5051", mtcher.group(1));
}

public void testZipCodeGroupException() throws Exception {
Matcher mtcher = pattern.matcher("22101-5051");
boolean isValid = mtcher.matches();
try {
mtcher.group(2);
fail("No exception was thrown");
} catch (IndexOutOfBoundsException e) {
}
}
}

JUnit 4 이전에는 픽스쳐의 이점을 얻기 위해서는 감수해야 하는 희생이 더 많았다.




위로


4.0에서의 유연성

JUnit 4에서는 주석을 사용하여 픽스쳐에 따른 상당한 오버헤드를 없앰으로써 모든 테스트에 대해 또는 전체 클래스에 대해 한 번 픽스쳐를 실행하거나 아예 실행하지 않을 수도 있다. 픽스쳐 주석은 클래스 수준의 픽스쳐 2개와 메서드 수준의 픽스쳐 2개가 존재한다. 클래스 수준의 경우 @BeforeClass@AfterClass가 있으며 메서드(또는 테스트) 수준의 경우 @Before@After가 있다.

Listing 10의 테스트 케이스에는 @Before 주석을 사용하여 두 테스트에 대해 실행되는 픽스쳐가 들어 있다.


Listing 10. 주석을 사용한 유연한 픽스쳐
                    
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.JUnit.BeforeClass;
import org.JUnit.Test;
import static org.JUnit.Assert.assertTrue;
import static org.JUnit.Assert.assertFalse;

public class RegularExpressionJUnit4Test {
private static String zipRegEx = "^\\d{5}([\\-]\\d{4})?$";
private static Pattern pattern;

@Before
public static void setUpBeforeClass() throws Exception {
pattern = Pattern.compile(zipRegEx);
}

@Test
public void verifyZipCodeNoMatch() throws Exception{
Matcher mtcher = this.pattern.matcher("2211");
boolean notValid = mtcher.matches();
assertFalse("Pattern did validate zip code", notValid);
}

@Test(expected=IndexOutOfBoundsException.class)
public void verifyZipCodeGroupException() throws Exception{
Matcher mtcher = this.pattern.matcher("22101-5051");
boolean isValid = mtcher.matches();
mtcher.group(2);
}
}




위로


1회용 픽스쳐

픽스쳐를 한 번만 실행해야 하는 경우는 어떻게 해야 할까? Listing 9처럼 이전 스타일의 데코레이터를 구현하는 대신 Listing 11에서와 같이 @BeforeClass 주석을 사용할 수 있다.


Listing 11. JUnit 4에서 1회용 픽스쳐 설정
                    
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.JUnit.BeforeClass;
import org.JUnit.Test;
import static org.JUnit.Assert.assertTrue;
import static org.JUnit.Assert.assertFalse;

public class RegularExpressionJUnit4Test {
private static String zipRegEx = "^\\d{5}([\\-]\\d{4})?$";
private static Pattern pattern;

@BeforeClass
public static void setUpBeforeClass() throws Exception {
pattern = Pattern.compile(zipRegEx);
}

@Test
public void verifyZipCodeNoMatch() throws Exception{
Matcher mtcher = this.pattern.matcher("2211");
boolean notValid = mtcher.matches();
assertFalse("Pattern did validate zip code", notValid);
}

@Test(expected=IndexOutOfBoundsException.class)
public void verifyZipCodeGroupException() throws Exception{
Matcher mtcher = this.pattern.matcher("22101-5051");
boolean isValid = mtcher.matches();
mtcher.group(2);
}
}

tearDown() 메서드

이전의 tearDown() 기능은 새로운 픽스쳐 모델에서 사라지지 않았다. tearDown()메서드를 실행하려면 새 메서드를 생성하고 필요에 따라 @After 또는 @AfterClass를 사용하면 된다.




위로


향상된 사용성

JUnit 4에서는 테스트 케이스에서 두 개 이상의 픽스쳐를 지정할 수 있다. 새로운 주석 중심의 픽스쳐에서는 여러 @BeforeClass 픽스쳐 메서드를 만드는 데 어떠한 제한도 없다. 하지만 현재 버전의 JUnit 4에서는 어떤 픽스쳐 메서드를 먼저 실행하도록 지정할 수 없으므로 두 개 이상의 픽스쳐를 사용할 때 이 점에 주의해야 한다.


--다음페이지--

테스트 실행: JUnit 4에서 테스트

새 롭게 향상된 JUnit 4에서 가장 놀라운 특징 중 하나는 테스트를 논리적으로 그룹화하고 이를 단일 유닛으로 실행하는 데 사용되는 메커니즘인 스위트가 없다는 점이다. 이 섹션에서는 스위트를 대신하는 효율적인 새로운 주석 기능에 대해 소개하고 이클립스 및 앤트에서 JUnit 4 테스트를 실행하는 방법을 보여준다.

이전 방식의 스위트

차이점을 비교해 볼 수 있도록 Listing 12에 표시된 이전 방식의 JUnit 스위트를 확인해 보자(이 스위트는 두 개의 논리적 테스트 클래스를 그룹화하고 이를 단일 유닛으로 실행한다).


Listing 12. 이전 방식의 JUnit 스위트
                    
import JUnit.framework.Test;
import JUnit.framework.TestSuite;

public class JUnit3Suite {

public static Test suite() {
TestSuite suite = new TestSuite();
suite.addTest(OneTimeRegularExpressionTest.suite());
suite.addTestSuite(RegularExpressionTest.class);
return suite;
}
}




위로


두 가지 뛰어난 새로운 주석 기능

JUnit 4에서 스위트는 새로운 주석 두 가지로 대체되었다. 첫 번째로 @RunWith는 프레임워크에 내장된 러너(runner)가 아닌 다른 러너를 통해 특정 테스트 클래스를 손쉽게 실행할 수 있게 해준다. JUnit 4는 @RunWith 주석에서 지정해야 하는 Suite라는 이름의 스위트 러너를 번들로 포함한다. 또한 테스트 스위트를 나타내기 위한 클래스 목록을 매개변수로 취하는 @SuiteClasses라는 주석을 제공해야 한다.


Listing 13. 편리한 기능의 주석
                    
import org.JUnit.runner.RunWith;
import org.JUnit.runners.Suite;
import org.JUnit.runners.Suite.SuiteClasses;

@RunWith(Suite.class)
@SuiteClasses({ParametricRegularExpressionTest.class,
RegularExpressionTest.class,
TimedRegularExpressionTest.class})
public class JUnit4Suite {

}

새로운 JUnit 4 주석이 어렵게 보이더라도 걱정할 필요는 없다. JUnit 4를 고안한 개발자들도 비슷한 생각을 갖고 있다. Javadocs에서 JUnit 개발자들은 "사람들이 실제로 사용하는 방식대로" 러너 API가 변화될 것으로 예상한다고 설명한다. 최소한 이들은 이점에서 솔직하다.

이클립스에서 JUnit 4 테스트 실행

이클립스와 같은 IDE에서 또는 명령행을 통해 JUnit 4 테스트 클래스를 실행할 수 있다. Run As JUnit 테스트 옵션을 선택하면 이클립스 버전 3.2 이상에서 JUnit 테스트를 실행할 수 있다. 명령행을 통해 테스트를 실행하려면 org.JUnit.runner.JUnitCore 클래스를 실행하고 테스트의 정규화된 이름을 인수로 전달해야 한다.

예를 들어 이클립스에서 번들로 제공되는 JUnit 러너를 사용하지 않고자 하는 경우 새로운 실행 구성을 정의하고 그림 2와 같이 JUnitCore 클래스를 지정하면 된다.


그림 2. 이클립스에서 JUnit 4 명령행 테스트를 실행하기 위한 첫 번째 단계

테스트 지정

그런 다음 그림 3과 같이 Arguments 탭의 "Program arguments" 텍스트 상자에 테스트의 정규화된 이름을 추가하여 실행할 테스트를 지정해야 한다.


그림 3. 이클립스에서 JUnit 명령행 테스트를 실행하기 위한 두 번째 단계




위로


앤트와 JUnit 4

앤 트와 JUnit은 지금까지 훌륭한 팀으로 존재해 왔으며 많은 개발자들은 이러한 관계로 인해 뛰어난 JUnit 4를 얻게 될 것이라고 기대했다. 그리고 결과적으로도 이러한 사실은 실제로 나타났다. 1.7 이전의 앤트 버전을 실행 중인 경우 JUnit 4 테스트를 즉시 실행할 수 없다. 하지만 그렇더라도 테스트 자체를 실행할 수 없는 것은 아니며 단지 즉시 실행할 수 없을 뿐이다.

잘못 맞춰진 짝

1.7 이전의 앤트 버전에서 JUnit 4 테스트(Listing 14 참조)를 실행하면 흥미로운 결과가 발생한다.


Listing 14. 간단한 JUnit 4 테스트 클래스
                    
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.JUnit.BeforeClass;
import org.JUnit.Test;
import static org.JUnit.Assert.assertTrue;

public class RegularExpressionTest {
private static String zipRegEx = "^\\d{5}([\\-]\\d{4})?$";
private static Pattern pattern;

@BeforeClass
public static void setUpBeforeClass() throws Exception {
pattern = Pattern.compile(zipRegEx);
}

@Test
public void verifyGoodZipCode() throws Exception{
Matcher mtcher = this.pattern.matcher("22101");
boolean isValid = mtcher.matches();
assertTrue("Pattern did not validate zip code", isValid);
}
}

여러 번의 테스트 실패

앤트에서 오래된 JUnit 작업을 사용하면 Listing 15와 같은 에러가 발생한다.


Listing 15. 여러 가지 에러
                    
[JUnit] Running test.com.acme.RegularExpressionTest
[JUnit] Tests run: 1, Failures: 1, Errors: 0, Time elapsed: 0.047 sec
[JUnit] Testsuite: test.com.acme.RegularExpressionTest
[JUnit] Tests run: 1, Failures: 1, Errors: 0, Time elapsed: 0.047 sec

[JUnit] Testcase: warning took 0.016 sec
[JUnit] FAILED
[JUnit] No tests found in test.com.acme.RegularExpressionTest
[JUnit] JUnit.framework.AssertionFailedError: No tests found in
test.com.acme.RegularExpressionTest
[JUnit] Test test.com.acme.RegularExpressionTest FAILED

해결 방법

1.7 이전의 앤트 버전에서 JUnit 4 테스트를 실행하려면 Listing 16에서와 같이 JUnit4TestAdapter의 인스턴스를 반환하는 suite() 메서드를 사용하여 테스트 케이스를 수정해야 한다.


Listing 16. 이전 메서드를 새롭게 활용
                    
public static JUnit.framework.Test suite(){
return new JUnit4TestAdapter(RegularExpressionTest.class);
}

이 인스턴스에서는 이름이 비슷한 @Test 주석으로 인해 Test의 반환 유형을 정규화해야 한다. 하지만 suite() 메서드를 배치하면 어떤 버전의 앤트에서도 JUnit 4 테스트가 문제없이 실행된다.


--다음페이지--

매개변수 테스트

애플리케이션의 비즈니스 로직에서는 테스트가 제대로 될 때까지 사용자가 매우 많은 테스트를 작성해야 한다. 이전 버전의 JUnit에서 이러한 유형의 시나리오는 테스트에서 메서드에 대한 매개변수 그룹이 다양하면 각 고유 그룹에 대한 테스트 케이스를 작성해야 했기 때문에 매우 많은 불편을 초래했다.

JUnit 4에서는 매개변수 값을 지정할 수 있는 일반 테스트를 작성할 수 있게 해주는 새로운 기능이 도입되었다. 결과적으로 테스트 케이스 하나를 작성하여 이전에 작성한 각 매개변수에 대해 이를 여러 번 실행할 수 있다.

간단한 매개변수를 통한 테스트

JUnit 4에서 매개변수 테스트를 작성하는 데에는 다음과 같이 간단한 5단계로 이루어진다.

  1. 매개변수를 사용하지 않는 일반 테스트를 작성한다.
  2. Collection 유형을 반환하는 static 피더 메서드를 작성하고 @Parameter 주석으로 표시한다.
  3. 첫 번째 단계에서 정의한 일반 메서드에 필요한 매개변수 유형에 대한 클래스 멤버를 만든다.
  4. 이러한 매개변수 유형을 사용하고 이를 세 번째 단계에서 정의한 클래스 멤버와 연결하는 생성자를 만든다.
  5. @RunWith 주석을 통해 Parameterized 클래스와 함께 실행할 테스트 케이스를 지정한다.

이러한 단계들을 차례로 살펴보자.

첫 번째 단계. 일반 테스트 작성

Listing 17에서는 정규식에 대해 여러 값을 확인하는 일반 테스트를 보여준다. 여기에서는 phrasematch 값이 정의되지 않았다.


Listing 17. 일반 테스트
                    
@Test
public void verifyGoodZipCode() throws Exception{
Matcher mtcher = this.pattern.matcher(phrase);
boolean isValid = mtcher.matches();
assertEquals("Pattern did not validate zip code", isValid, match);
}

두 번째 단계. 피더 메서드 작성

다음 단계는 피더 메서드를 작성하는 것이다. 이는 static 으로 선언해야 하고 Collection 유형을 반환해야 한다. 이 메서드는 @Parameters a주석으로 표시해야 한다. Listing 18에서와 같이 메서드 내에서 다차원 Object 배열을 만들고 이를 List로 변환한다.


Listing 18. @Parameters 주석으로 표시된 피더 메서드
                    
@Parameters
public static Collection regExValues() {
return Arrays.asList(new Object[][] {
{"22101", true },
{"221x1", false },
{"22101-5150", true },
{"221015150", false }});
}

세 번째 단계. 클래스 멤버 두 개 작성

매개변수 유형은 Stringboolean이기 때문에 다음과 같이 클래스 멤버를 두 개 작성해야 한다.


Listing 19. 클래스 멤버 두 개 선언
                    
private String phrase;
private boolean match;

네 번째 단계. 생성자 작성

다음으로 작성하는 생성자는 Listing 20에서와 같이 클래스 멤버를 매개변수 값에 연결한다.


Listing 20. 값을 비교하는 생성자
                    
public ParametricRegularExpressionTest(String phrase, boolean match) {
this.phrase = phrase;
this.match = match;
}

다섯 번째 단계. Parameterized 클래스 지정

마지막으로 클래스 수준에서 이 테스트가 Listing 21에서와 같이 Parameterized 클래스로 실행되도록 지정한다.


Listing 21. Parameterized와 @RunWith 주석 지정
                    
@RunWith(Parameterized.class)
public class ParametricRegularExpressionTest {
//...
}




위로


테스트 실행

테스트 클래스를 실행하면 일반 verifyGoodZipCode() 테스트 메서드가 Listing 18의 regExValues() 데이터 피더 메서드에 정의된 각 값 쌍에 대해 한 번씩 네 번 실행된다.

예를 들어 이 테스트를 이클립스에서 실행하면 그림 4에서와 같이 테스트 실행을 4회 했음을 보고한다.


그림 4. 이클립스에서 실행된 매개변수 테스트


--다음페이지--

기타 새로운 기능

지금까지 설명한 중요한 변경 사항 외에도 JUnit 4에는 몇 가지 추가된 기능과 없어진 기능이 있다. 그 예로 assert 메서드가 새로 추가되었고 터미널 상태가 없어졌다.

새로운 assert

JUnit 4에는 배열 내용을 비교하기 위한 새로운 assert 메서드가 추가되었다. 그렇게 중요한 기능은 아니지만, 덕분에 사용자는 더 이상 배열의 내용을 반복적으로 검사하여 각 개별 항목을 확인할 필요가 없어졌다.

예를 들어 Listing 22에 보이는 코드는 이전 버전의 JUnit에서는 사용할 수 없다. 이 테스트 케이스는 각 배열의 두 번째 요소가 조금 다르기 때문에 실패한다.


Listing 22. JUnit 4에서 배열을 지원하는 assertEquals
                    
@Test
public void verifyArrayContents() throws Exception{
String[] actual = new String[] {"JUnit 3.8.x", "JUnit 4", "TestNG"};
String[] var = new String[] {"JUnit 3.8.x", "JUnit 4.1", "TestNG 5.5"};
assertEquals("the two arrays should not be equal", actual, var);
}




위로


에러 표시 안 함

JUnit 4에서 사소할 수도 있지만 중요한 변경 사항 중 하나는 에러 표기가 사라졌다는 점이다. 이전 버전에서는 실패 개수와 에러 개수가 모두 보고되었지만 JUnit 4에서는 테스트가 성공하거나 실패하는 것만 표시된다.

흥미롭게도 하나의 상태가 제거되었지만 이번에는 테스트를 무시하는 기능으로 인해 새로운 상태가 추가되었다. 일련의 테스트를 실행하면 JUnit 4에서는 실행된 테스트 개수와 실패 개수, 무시된 테스트 개수를 보고한다.


결론

JUnit 4가 원래의 설계 의도와 많이 달라졌지만 그렇다고 해서 이 프레임워크가 완전히 다른 방식으로 작동하는 것은 아니다. 원래의 프레임워크가 갖고 있는 성능과 단순성은 그대로 유지된다. 실제로 프레임워크를 자세히 살펴보면 일부 뛰어난 새 기능들이 추가되었지만 개발자의 테스트 기술을 혁신적으로 이끌었던 중요한 원칙은 그대로 남아 있다는 것을 알 수 있다.

본 튜토리얼에서는 테스트 선언에서 매개변수 테스트까지 JUnit 4의 전반적인 기능을 확인하기 위한 단계들을 살펴보았다. 제한 시간 테스트 및 예외 테스트와 같은 새로운 기능을 확인하고 픽스쳐 및 논리적인 그룹화와 같은 익숙한 기능의 변경 사항도 확인했다. 또한 이클립스에서 수행되는 테스트 방식을 살펴보고 1.7 이전 버전을 포함하여 모든 앤트 버전에서 테스트를 실행할 수 있게 해주는 간단한 해결 방법도 배웠다.

본 튜토리얼에서 독자가 반드시 알았으면 하는 내용이 있다면 주석이 JUnit의 본래 기능을 헤치는 것이 아니라 아주 손쉽게 사용할 수 있다는 사실이다. 따라서 독자들도 주석을 시험해 보기를 바란다. 주석은 테스트 작성 방식을 한층 더 세련되게 그리고 편리하게 만들어 줄 것이다.

기사의 원문보기


참고자료


필자소개

Andrew Glover는 Stelligent Incorporated의 회장이다. 효과적인 개발자 테스팅 전략과 통합 기술력을 바탕으로 기업이 소프트웨어 품질을 높일 수 있도록 돕고 있다.