사용환경은 eclipse 3.2 JDK 1.4.2 , Junit 3.8.1
먼저 해야될 일은 eclipse 에서 java 프로젝트에 junit.jar 를 import 해야한다.
Project 에서 오른쪽 마우스 클릭하여 properties 선택한다.
Java Build Path > Libraries 탭을 선택하고 오른쪽에 Add Exteranl JARS .. 선택하여
그림과 같이 다운받아서 설치해놓은 eclipse 폴더의 junit.jar 링크한다.
다른 방법은 eclipse 에 junit 을 설치 했다면 add Library 클릭해서 나오는 화면에 junit 이 추가되어있다.
이것을 선택하면된다
현재 2가지의 junit 이 설치되어있는 것이 보일것이다.
추가된화면이다.
이제 testcase 파일을 만들어본다. 마우스를 패키지에 가져가서 오른쪽마우스 클릭 > New
> Junit Test Case 클릭
기본설정된 내용을 그대로 사용한다.
Which method stubs would you like to create? 란은 3가지 함수는 TestCase 클래스의 함수를 상속해서 사용할건지를 묻는 것인데 setUp() 은 클래스 초기화를 할 때 쓰는 함수이며 tesrDown() 은 클래스 종료시에 호출되는 함수이다.
상속하는게 없으면 finish 누르고 끝내지만 아래 그림과 같이 Class under test란에 클래스를
선택하게 되면 함수 리스트가 나오게 되는데 그 함수중 선택을 하게 되면 테스트 케이스는 그것을 실행하게 된다.
선택한 클래스에서 사용할 함수목록들이 나와있다. 선택하고 finish 를 클릭한다.
import junit.framework.TestCase;
import org.apache.log4j.Logger;
class Fibo{
private Logger log = Logger.getLogger(this.getClass());
public int get(int n){
int result;
if (n == 1 || n == 2){
result = 1;
}else{
result = get(n-1) + get(n-1);
}
log.debug(Integer.toString(result));
return result;
}
}
public class WorkingStepMainTest extends TestCase {
protected void setUp() throws Exception {
super.setUp();
}
public void testMain(){
Fibo fibo = new Fibo();
assertEquals(2, fibo.get(1));
assertEquals(1, fibo.get(2));
assertEquals(fibo.get(1)+fibo.get(2), fibo.get(3));
assertEquals(fibo.get(2)+fibo.get(3), fibo.get(4));
assertEquals(55, fibo.get(10));
}
}
다음은 위의 소스를 실행해본다.
그럼 junit 테스트 perspective 가 나타나면서 결과를 왼쪽에 보여준다.
그림에서 보는 바와 같이 수행시간, 실행한 개수 , 에러 개수. 실패갯수 가 나오며 아래쪽에 Failure Trace 를 보게 되면 실패한 에러내용과 위치가 표시 되어있다, 클릭하게 되면 그 위치로 간다.
아래와 같이 여러 케이스의 함수를 설정해놓고 테스트를 해가면 편리할것이다.
assertEquals(2, fibo.get(1));
assertEquals(1, fibo.get(2));
assertEquals(fibo.get(1) + fibo.get(2), fibo.get(3));
테스트에 쓰이는 함수들은 Assert.class 에 이쓴ㄴ데 그 클래스를 열어보면 아래와 같이
많은 함수들이 있다. 주석으로 설명이 잘 되어있으므로 자기가 테스트하고자 하는 적당한
함수를 골라 쓰면 될것이다.
assertEquals(x, y) : x 와 y 가 같으면 테스트 통과
assertFalse(b) : b가 false 이면 테스트 통과
assertTrue(b) : b가 true 이면 테스트 통과
assertNull(o) : 객체 o 가 null 이면 테스트 통과
assertNotNull(o) : 객체 o 가 null 이 아니면 테스트 통과
assertSame(ox, oy) : ox 와 oy 가 같은 객체를 참조하고 있으면 테스트 통과
assertNotSame(ox, oy) : ox 와 oy 가 같은 객체를 참조하고 있지 않으면 통과
public class Assert
{
protected Assert()
public static void assertTrue(String message, boolean condition)
public static void assertTrue(boolean condition)
public static void assertFalse(String message, boolean condition)
public static void assertFalse(boolean condition)
public static void fail(String message)
public static void fail()
public static void assertEquals(Object expected, Object actual)
public static void assertNotNull(Object object)
public static void assertNull(Object object)
public static void assertSame(String message, Object expected, Object actual)
public static void assertNotSame(Object expected, Object actual)
private static void failSame(String message)
private static void failNotSame(String message, Object expected, Object actual)
private static void failNotEquals(String message, Object expected, Object actual)
static String format(String message, Object expected, Object actual)
}
등등 다른 함수들도 많이 있으니 참고하자.
여기서 체크해 봐야할것이 에러를 출력하는 객체가 뭐냐하는것인데 모든 함수는 fail 이라는 함수를 호출하게 되는데 이 함수의 내용은 다음과 같다.
public static void fail(String message){
throw new AssertionFailedError(message);
}
AssertionFailedError 객체를 throw 로 던지게 된다.
이 객체는 Error 객체를 상속받아 구현된 클래스 인데
public class AssertionFailedError extends Error
{
public AssertionFailedError(){}
public AssertionFailedError(String message){
super(message);
}
}
Error 객체는 다음과 같다. 결국엔 Throwable 을 상속받은 Error 객체를 쓰는것이다.
이런 식으로 파고 들다보면 설계자의 의도를 알수 있으며 이 설계는 공인된 구조여서
학습에 많은 도움을 줄뿐만아니라 조금만 응용하면 프로젝트에서 유용하게 사용할수 있을
것이다.
자기가 Error 객체를 하나 만들어 프로젝트에 활용하고 싶다면 위와 같은 패턴으로
Throwable 를 상속받아 입맛에 맞게 고쳐 적용하면될것이다.
public class Error extends Throwable{
public Error(){}
public Error(String s){
super(s);
}
public Error(String s, Throwable throwable){
super(s, throwable);
}
public Error(Throwable throwable){
super(throwable);
}
static final long serialVersionUID = 4980196508277280342L;
}
서론
- 모든 소스는 Copy & Paste 만으로 실행할수 있다.
준비
JUnit 3 vs JUnit 4
3.x | 4.4 | |
test 작성 | TestCase 를 상속받은 객체의 test로 시작하는 함수 | @Test 이 붙은 함수 |
test 실행 | Console 용, Swing 용 러너 제공 대부분 IDE에 통합 | Console 용 러너 제공, Swing 러너 삭제 (이제 거의 모든 Java IDE에서 JUnit GUI Runner제공) |
실행순서 | setUp testXXX tearDown |
@BeforeClass(반드시 static method) @Before @Test @After @AfterClass(반드시 static method) |
assert | TestCase 에 정의된 assert 문들 사용 (내부적으로 assert문은 정적 선언되어 있다.) |
Assert 에 정의된 정적 assert 문들 사용, assertThat 이 추가되었다. |
기타 | test대상 메소드의 객체가 TestCase를 상속받아야함 | x |
실행 예제
- JUnit 3.8
import static java.util.Arrays.asList; import junit.framework.TestCase; public class SimpleTest extends TestCase { private static int number; private static Integer staticNumber; public void setUp() { number = 10; } public void testSimple() { assertEquals(10, number); assertEquals( asList(new Integer[]{1,2,10}), asList(new Integer[]{1,2,number})); assertTrue(10 == number); assertTrue( asList(new String[]{"1"}).contains("1")); assertTrue("123".contains("1")); assertNull(staticNumber); } public void testDivideByZero() { try { assertEquals(0, number / 0); } catch (ArithmeticException e) { return; } fail(); } // 실행 방지를 위해 _ 첨가 public void _testMultiply() { assertEquals(100, number); } public void tearDown() { number=0; } }
- JUnit 4.4
import static org.hamcrest.CoreMatchers.*; import static org.junit.Assert.*; import static org.junit.matchers.JUnitMatchers.*; import org.junit.*; import static java.util.Arrays.asList; public class SimpleTest { private int number; private static Integer staticNumber; @BeforeClass public static void beforeClass() { staticNumber = 10; } @Before public void setUpNumber() { number = 10; } @Test public void simple() { assertEquals(10, number); assertArrayEquals( new Integer[]{1,2,10}, new Integer[]{1,2,number}); assertTrue(10 == number); assertTrue( asList(new String[]{"1"}).contains("1")); assertTrue("123".contains("1")); assertNotNull(staticNumber); assertThat(number,is(10)); assertThat( asList(new String[]{"1"}),hasItem("1")); assertThat("123",containsString("1")); assertThat(staticNumber,is(notNullValue())); } @Test(expected = ArithmeticException.class) public void divideByZero() { assertEquals(0, number / 0); } @Ignore("not ready yet") @Test public void multiply() { assertEquals(100, number); } @After public void clearNumber() { number=0; } @AfterClass public static void afterClass() { staticNumber = null; } }
JUnit 4.4 에서 추가된 요소
assertThat - Hamcrest - library of matchers for building test expressions
assertThat([값], [matcher 문법])
String actual = "A"; assertEquals("A", actual);이 형태의 코드는 다음과 같이 표현될 수 있다.
String actual = "A"; assertThat(actual , is("A")); //That actual is "A"
import static org.hamcrest.CoreMatchers.*; import static org.junit.Assert.assertThat; import static org.junit.Assert.assertTrue; import static org.junit.matchers.JUnitMatchers.containsString; public class SimpleTest { String responseString = "color col"; @Test public void usingAssertTrue() { assertTrue(responseString.contains("color") && responseString.contains("colour")); } @Test public void usingAssertThat() { assertThat(responseString, is(allOf(containsString("color"), containsString("colour")))); // That responseString is a containning string "color" and a containning string "colour". } }
TestCase.assertTrue 의 결과
Assert.assertThat 의 결과
JUnit 4.4 에 포함된 Matcher들을 손쉽게 사용하기 위해서, JUnit 4.4에서는 CoreMatcher 와 JUnitMater 속에 라이브러리 상에서 제공하는 대부분의 Matcher들을 static 형태로 포함시켜 두었다.
import static org.hamcrest.CoreMatchers.*; import static org.junit.matchers.JUnitMatchers.*;
Assumption, Theory Proper library
public void test1(){ if(new File(EXAMPLE_PATH).exists() == false) return; // ... 테스트 코드 }
@Before public void before(){ Assume.assumeThat(new File(EXAMPLE_PATH).exists(), is(true)); } @Test public void test1(){ FileReader fr = new FileReader(EXAMPLE_PATH); // ... 테스트 코드 }
import static org.hamcrest.CoreMatchers.*; import static org.junit.Assert.assertThat; import static org.junit.Assume.assumeThat; import static org.junit.matchers.StringContains.containsString; import org.junit.experimental.theories.DataPoint; import org.junit.experimental.theories.Theories; import org.junit.experimental.theories.Theory; import org.junit.experimental.theories.suppliers.TestedOn; import org.junit.runner.RunWith; @RunWith(Theories.class) public class TheoryExample { public class User { private String username; public User(String username) { this.username = username; } public String getUsername(){ return this.username; } } @DataPoint public static String GOOD_USERNAME = "optimus"; @DataPoint public static String USERNAME_WITH_SLASH = "optimus/prime"; @Theory public void filenameIncludesUsername(String username) { assumeThat(username, not(containsString("/"))); assertThat(new User(username).getUsername(), containsString(username)); } @SuppressWarnings("unchecked") @Theory public void multiplyIsInverseOfDivideWithInlineDataPoints( @TestedOn(ints = { 0, 5, 10 }) int amount, @TestedOn(ints = { 0, 1, 2 }) int m) { assumeThat(m, not(0)); assertThat(amount*m/m, is(amount)); } }
JUnit 4 에서는 TestCase를 만들기는 쉽다. 그런데 TestSuite 어느 문서에 나온거야?
public class AllTests { public static Test suite() { TestSuite suite = new TestSuite("Test for default package"); //$JUnit-BEGIN$ suite.addTestSuite(SimpleTest.class); //$JUnit-END$ return suite; } }
package test; import org.junit.runner.RunWith; import org.junit.runners.Suite; @RunWith(Suite.class) @Suite.SuiteClasses( { SimpleTest.class,SimpleTest2.class}) public class AllTests { }
static import가 귀찮다.
import static org.hamcrest.CoreMatchers.is; import static org.junit.Assert.assertThat; ... assertThat("A", is("A"); ...
Eclipse에서 곧 바로 JavaDoc을 보고 싶다.
String example = "example";
결론
출처 : http://dna.daum.net/
댓글