소프트웨어공학개론 Tutorial #2: Junit Eun Man Choi emchoi@dgu.ac.kr
강의목표 l JUnit 소개 l 테스트케이스 l Assertion l JUnit 테스트실행 2
JUnit l Java 언어를위한단위테스팅프레임워크 l 저자 : Erich Gamma, Kent Beck l 목적 : l 테스트를생성하고실행하기쉽다면프로그래머가테스트를생성하고실행하도록마음을움직일것이다. 3
소개 l 테스트를자동화하기위하여무엇이필요한가? l 테스트스크립트 l 테스트대상시스템 (SUT) 에보내는액션 l SUT 에예상되는반응 l 테스트가성공이냐실패냐를결정하는방법 l 테스트실행시스템 l 스크립트를읽어테스트케이스를 SUT 에연결시키는메카니즘 l 테스트결과를추적 4
테스트케이스판결 l 판결 (verdict) 은단일테스팅을실행한결과의선언 l 성공 (Pass): 테스트케이스가의도한목적을이루고테스트대상이예상되는결과를수행함 l 실패 (Fail): 테스트케이스가의도한목적을성취하였으나테스트대상이예상된대로수행하지못함 l 오류 (Error): 테스트케이스가의도한목적을성취하지못함 l 이유 : 테스트케이스수행도중예상하지못한이벤트발생 테스트케이스가적절히셋업되지않음 5
JUnit 버전 l 2007 년 3 월부터현재의버전 4.3.1 l JUnit 4.x 를사용하려면 Java version 5 나 6 을사용하여야 l 2006 년 4 월에소개된 JUnit 4 는이전버전에서상당한변화 ( 호환성없음 ) l JUnit 4 를소개 l 대부분의 JUnit 문서와사례는현재 JUnit 3 를사용하여상당히다름 l JUnit 3 은 Java (1.4.2) 낮은버전에서사용가능. l junit.org 웹사이트는오래된버전의요구가없는한 JUnit version 4 을사용 l Eclipse (3.2) 는플러그인으로두가지버전 JUnit 3.8 나 JUnit 4.1 중고를수있게함 6
JUnit 테스트란? l 테스트스크립트는 Java 메소드의모임 l 일반적인아이디어는 Java 객체를생성하고이것으로뭔가관심있는일을하고객체가올바른특성을가지고있는지결정하는것 l 추가할것은? Assertions. l 여러가지특성을체크하기위한메소드의패키지 : 객체의동질성 equality 동일한객체참조 null / non-null 객체참조 l assertions 은테스트케이스판결을결정하기위하여사용됨 7
Junit 은언제사용하여야하나? l 이름에있는것처럼 l 적은분량의단위테스팅을위하여 l 즉복잡한테스팅이나시스템테스팅은거리가멈 l 테스트중심개발방법에서 JUnit 테스트는코드개발전에테스트가먼저작성되어실행됨 l 구현코드는테스트를통과하기위한최소의코드로작성되어야함 즉추가되는기능이없어야 l 코드가일단작성되면계속테스트를실행하여통과되어야 l 새로코드가추가될때마다모든테스트를재실행하여이상을일으키지않음을증명하여야 8
JUnit 4 테스트케이스 /** Test of setname() method, of class Value */ @Test public void createandsetname() { Value v1 = new Value( ); v1.setname( "Y" ); String expected = "Y"; String actual = v1.getname( ); Assert.assertEquals( expected, actual ); 9
JUnit 4 테스트케이스 /** Test of setname() method, of class Value */ @Test public void createandsetname() { Value v1 = new Value( ); v1.setname( "Y" ); 이 Java 메소드는테스트케이스임을테스트실행자에게표시 String expected = "Y"; String actual = v1.getname( ); Assert.assertEquals( expected, actual ); 10
JUnit 4 테스트케이스 /** Test of setname() method, of class Value */ @Test public void createandsetname() { Value v1 = new Value( ); v1.setname( "Y" ); String expected = "Y"; String actual = v1.getname( ); 목적 : setname 이 Value 객체에특정이름을저장하였는지확인 Assert.assertEquals( expected, actual ); 11
JUnit 4 테스트케이스 /** Test of setname() method, of class Value */ @Test public void createandsetname() { Value v1 = new Value( ); v1.setname( "Y" ); String expected = "Y" String actual = v1.getname( ); Value 객체가정말이름을저장하였는지확인하기위하여호출 Assert.assertEquals( expected, actual ); 12
JUnit 4 테스트케이스 /** Test of setname() method, of class Value */ @Test public void createandsetname() { Value v1 = new Value( ); v1.setname( "Y" ); expected 와 actual 는같기를희망 같지않다면테스트케이스는 fail String expected = "Y"; String actual = v1.getname( ); Assert.assertEquals( expected, actual ); 13
Assertions l 가설 (assertion) 은 Junit 에서 Assert 라는클래스로정의 l assertion 가참이면메소드의실행은계속됨 l 어떤 assertion 이거짓이면메소드의실행은그자리에서중지되고테스트케이스의결과는실패 (fail). l 메소드수행중예외가발생하면테스트케이스의결과는 error. l 모든메소드에서가설 (assertion) 이위배되지않았다면테스트케이스는통과 (pass) l 모든 assertion 메소드는정적 (static) 14
Assertion 메소드 (1) l 진위조건이 true 나 false asserttrue(condition) assertfalse(condition) l 객체가 null 이냐 null 이아닌가? assertnull(object) assertnotnull(object) l 객체가동일한가 ( 즉같은객체를참조하고있나 ) 아닌가? assertsame(expected, actual) true if: expected == actual assertnotsame(expected, actual) 15
Assertion 메소드 (2) l 객체의동일성 ( Equality ): assertequals(expected, actual) expected.equals( actual ) 이면참 l 배열의동일성 ( Equality ): assertarrayequals(expected, actual) 배열은같은길이를가져야함 모든 i의정상적인값에대하여다음을체크 : assertequals(expected[i],actual[i]) 또는 assertarrayequals(expected[i],actual[i]) l 항상 fail 로판결되는무조건적실패 assertion fail() 이있음 16
Assertion 메소드매개변수 l 모든 assertion 메소드는 2 개의매개변수를가짐. 첫매개변수는예상되는값 (expected value) 두번째매개변수는실제값 (actual value) 이됨 l 순서가비교에는영향이없으나사용자에게실패메시지를생성할때이런순서로간주 l 모든 assertion 메소드는첫매개변수로추가 String 파라미터를가질수있음. 스트링은 assertion 이실패로끝나면 failure 메시지에포함됨 l 예 : fail( message ) assertequals( message, expected, actual) 17
동일성 (Equality) assertions l assertequals(a,b) 는테스트대상클래스의 equals() 메소드에영향을받음. l a.equals( b ) 의결과에좌우됨 l 동일성관계를결정하는것은테스트대상클래스에달려있음 JUnit 은적용가능한것을사용 l 테스트대상클래스가 equals() 메소드를재정의하지않으면 Object 클래스로부터받은 default equals() 메소드를적용하여객체동일성을체크. l a 와 b 가 int, boolean, 등기본타입이라면 assertequals(a,b) 이다음과같이동작 : l a 와 b 가동일객체 (Integer, Boolean, 등 ) 로변환된후 a.equals( b ) 가계산됨 18
변동소수점 assertions l 변동소수점타입 (double 이나 float) 가비교될때는매개변수 delta 가추가로필요. l assertion 은다음을계산 Math.abs( expected actual ) <= delta 변동소수점비교에서 round-off 오류를피하기위하여 l 예 : assertequals( adouble, anotherdouble, 0.0001 ) 19
JUnit 테스트의구성 l 각메소드는독립적으로판결 (pass, error, fail) 될수있는테스트케이스를나타냄. l 일반적으로하나의 Java 클래스를위한모든테스트는분리된클래스안에모여그루핑됨. l 코딩스타일 ( 예 ): l 테스트대상클래스 : Counter l 테스트를포함한클래스 : CounterTest 20
Junit 테스트사례 public class Counter { int count = 0; public int increment() { return count += 1; public int decrement() { return count -= 1; l 메소드내부가구현되지않았더라도 Junit 테스트코딩가능함 l 명세만정해져있어도테스트코딩가능 l 메소드스텁이용 public int getcount() { return count; 21
Counter 를위한 JUnit 테스트 public class CounterTest { Counter counter1; // declare a Counter here @Before void setup() { counter1 = new Counter(); // initialize the Counter here @Test public void testincrement() { asserttrue(counter1.increment() == 1); asserttrue(counter1.increment() == 2); @Test public void testdecrement() { asserttrue(counter1.decrement() == -1); l 각테스트케이스는새로운 cointer 로시작 l 테스트케이스실행순서의미없음 22
테스트기반 (fixture) l 테스트기반은테스트케이스가실행되는배경 l 테스트기반은다음을포함 : l 테스트케이스에의하여사용될수있는객체나자원. l 객체를사용할수있게만들고자원을할당또는해지하는데필요한작업 : setup 과 teardown. 23
Setup 과 Teardown l 특정클래스를위한테스트셋에대하여각테스트케이스수행에앞서이루어져야하는반복적인작업이있음. l 예 : 작업하려는 관심대상 객체의생성, 예를들면네트워크연결. l 테스트케이스끝에는수행후청소하기 ( 객체삭제등 ) 위한반복되는작업이있음. l 자원할당이해지되고다음테스트케이스를위한상태로바뀌었는지확인 l 테스트케이스가실패하면테스트메소드의수행이거기서끝나게되어청소하는코드는실행될수없음. 24
Setup 과 Teardown l Setup: l 각테스트케이스전에수행될메소드에는 @Before 라는주석을사용 l Teardown ( 판결에상관없이 ): l 각테스트케이스뒤에수행될코드를가진메소드에는 @After 주석을사용 l 이런메소드는테스트케이스에서예외가발생하거나 assertion 이실패되더라도실행될것임 l 주석의수는제한없음 l @Before 주석을가진모든메소드는각테스트케이스실행전에수행되나순서는임의로. 25
예 : 파일을테스트기반으로사용 public class OutputTest { private File output; @Before public void createoutputfile() { output = new File(...); @After public void deleteoutputfile() { output.delete(); @Test public void test1withfile() { // code for test case objective 26 @Test public void test2withfile() { // code for test case objective
메소드수행순서 1. createoutputfile() 2. test1withfile() 3. deleteoutputfile() 4. createoutputfile() 5. test2withfile() 6. deleteoutputfile() l assertion: test1withfile 이 test2withfile 보다먼저실행된다는보장은없음 27
단한번의 setup l 전체테스트클래스를위하여다른테스트전에, 다른어떤 @Before 메소드보다앞서메소드를한번만수행시킬수있는방법이있음 l 서버를기동시키거나통신을개시하는데유용함. 테스트할때마다닫고다시여는것은시간이많이걸리기때문 l @BeforeClass 주석으로표시 ( 메소드하나에서만사용가능이며 static 이되어야함 ): { @BeforeClass public static void anynamehere() // class setup code here 28
단하나의 tear down l 단하나의청소메소드도가능. 클래스안에있는모든테스트케이스가수행된후, 어떤 @After 메소드후에수행됨 l 서버를종료시키거나통신연결을끊을때사용. l @AfterClass 주석으로표시 ( 하나의메소드에만사용가능하며 static 이되어야 ): { @AfterClass public static void anynamehere() // class cleanup code here 29
예외테스팅 (1) l @Test 주석에파라미터를추가하면특정예외가테스트중에발생할수있음을예측. @Test(expected=ExceptedTypeOfException.class) public void testexception() { exceptioncausingmethod(); l 예외가발생하지않거나예측하지못한예외가발생한다면테스트는실패. l 즉메소드의종료시점에예외가발생하지않으면테스트케이스는실패임. l 예외메시지내용을테스트하거나예외가발생되는범위를제한하는것은다음슬라이드에있는방법을사용 30
예외테스팅 (2) l 예외 Catch, 예외발생이없으면 fail( ) 사용 public void testexception() { try { exceptioncausingmethod(); // If this point is reached, the expected // exception was not thrown. fail("exception should have occurred"); catch ( ExceptedTypeOfException exc ) { String expected = "A suitable error message"; String actual = exc.getmessage(); Assert.assertEquals( expected, actual ); 31
JUnit 3 l 현재 JUnit 3 에서 JUnit 4 로이전이이루어지고있음 l Eclipse 3.2 는 Eclipse 테스트및성능도구플랫폼은 JUnit 4 와동작하지않음. l Netbeans 5.5 는 JUnit 3 에만동작. l JUnit archive 에는다음두페키지가공존 l JUnit 3: junit.framework.* l JUnit 4: org.junit.* 32
JUnit in Eclipse l 테스트케이스생성하려면 File New Other... Java, JUnit, TestCase l 테스트할클래스의이름입력 테스트할클래스입력 자동으로채워짐
JUnit 실행 2. pulldown 메뉴선택 1. 테스트케이스선택 3. Run As JUnit Test 34
JUnit 실행결과 테스트결과 35
참고사이트 l http://www.junit.org l Junit 다운 l Junit 이용을위한많은정보 l http://sourceforge.net/projects/cppunit l Junit 의 C++ 버전 l http://www.thecoadletter.com l 테스트중심개발 (Test-Driven Development) 정보 36