BlueJ에서의단위테스트 Unit Testing in BlueJ Version 1.0 for BlueJ Version 1.3.0 한국어버전 1.0 BlueJ Version 1.3.0 用 Michael Kölling Mærsk Insitute University of Southern Denmark 번역 : 황석형선문대학교컴퓨터정보학부 Copyright C M. Kölling - 1 -
차 례 1. 소개 3 2. 단위테스트기능설정 5 3. 테스트클래스의생성 6 4. 테스트메소드의생성 7 5. 테스트시행 8 6. 테스트결과해석 12 7. 설비 (Fixture) 이란? 14 8. 테스트설비의생성과사용 15 9. 수작업에의한테스트메소드작성 16 10. 테스트먼저작성하기 17 11. 다중클래스테스트 18 12. 요약 19-2 -
1. 소개 요약 BlueJ 에서는 JUnit 를통합한형태의회귀테스트 (regression testing) 기능을제공한다. 1.1 튜토리얼문서에대하여 ( 취급범위와대상독자 ) 본튜토리얼문서에서는 BlueJ환경에서제공하고있는단위테스트기능을소개한다. 이미여러분들은 BlueJ의일반적인기능들에대하여익숙해있을것으로가정한다. 그렇지않을경우에는 BlueJ튜토리얼 문서를먼저읽어보기바란다. http://www.bluej.org/doc/documentation.html로부터 PDF문서를입수할수있다. 또한, 독자여러분들은단위테스트에대한 ( 또는, 적어도일반적인테스트에관한 ) 기본적인사항들에대해서알고있을것으로가정한다. 아래절에서는몇가지기본사항에대해서설명하도록한다. 1.2 단위테스트란? 단위테스트 (unit testing)" 라는용어는소프트웨어시스템을몇개의독립된요소들로분리하여개발단위별로테스트하는것을가리킨다. 객체지향시스템에서는, 이와같은개별단위들 (units) 로서클래스와메소드가이에해당한다. 따라서, 본문서에서 단위테스트 라함은 BlueJ환경하에서메소드와클래스에대한개별적인테스트를지칭한다. 본튜토리얼문서에서는체계적인단위테스트를지원하는 BlueJ툴에대해서설명한다. 독자여러분들이 BlueJ의상호작용적인특성에익숙하다면, 각메소드들을개별적으로상호작용하면서테스트하기수월하다는사실을발견하게될것이다. 이와같은특징을 임기응변식특화형테스트 (ad-hoc testing)" 라고부르기로한다. 특화형테스트는유용하지만체계적인테스트로서충분하지않다. BlueJ의단위테스트기능은테스트를기록하고재시행하기위한도구를제공한다. 이와같은도구에의해 ( 일반적으로시스템을변경한후에 ) 단위테스트를수월하게반복할수있게된다. 또한, 개발자는최근의변경에의해기존의기능들을훼손하지않음을보증할수있다. 이를회귀테스트 (regression testing) 라고부른다. 단위테스트와회귀테스트는고전적이지만, 최근의 XP(eXtreme Programming) 방법론 1) 뿐만아니라, Java를위한단위테스트도구인 JUnit 등에서최근까지도널리사용되고있는테스트방법론이다. 1) XP 에관한상세한사항들은, Kent Beck, "Extreme Programming Explained:Embrace Change" Addison Wesley, 1999. 와 http://www.xprogramming.com/xpmag/whatisxp.htm 등을참고하기바란다. - 3 -
JUnit는 Erich Gamma와 Kent Beck에의해제작된회귀테스트용프레임워크이다. http://www.junit.org로부터관련소프트웨어와다양한정보를얻을수있다. 1.3 BlueJ 에서의단위테스트 BlueJ의체계적인테스트도구는 JUnit을기반으로하고있다. 따라서, JUnit 사용에관한몇가지지식을알고있으면 BlueJ에서단위테스트를이해하는데도움이될것이다. 이에관한관련논문 ( 현재로서는제공되고있지않지만, 추후에제공예정 ) 을읽어보기바란다. 또한, JUnit의웹사이트도훌륭한출발점이될것이다. BlueJ의단위테스트는, JUnit의회귀테스트와 BlueJ의상호작용적인테스트기능을혼합한형태로제공된다. 이두가지테스트기법들이모두제공되고있다. 또한, 두가지시스템을조합한새로운기능도제공되고있다. 예를들면, 향후의회귀테스트를위한 JUnit테스트메소드들자동적으로생성하기위하여상호작용적인테스트순서를기록할수있다. 이에대한구체적인예는본문서의후반부에설명하도록한다. BlueJ의단위테스트기능은 Andrew Patterson에의해 Monash University에서박사과정연구의일환으로설계 / 구현되었다. - 4 -
2. 단위테스트기능의설정 요약테스트도구들은설정메뉴 (preferences) 에서설정변경을하므로써활성화된다. BlueJ에서는테스트기능이비활성화상태로초기화되어있다. 테스트도구를사용하기위해서는, " 도구-옵션... 을선택하고, 테스트도구활성화 (Show Unit Testing Tools) 레이블이붙어있는체크박스를선택하도록한다. 이와같이하면, BlueJ인터페이스화면에 3개의요소들 ( 메인창의툴바에몇가지버튼들과 recording" 지시자가활성화되고, 보기 메뉴에는 테스트결과보기 (Show Test Results) 가나타나며, 컴파일완료된클래스의팝업메뉴에는 테스트클래스생성 (Create Test Class)" 라는항목이활성화된다. - 5 -
3. 테스트클래스생성 요약클래스의팝업메뉴에서 테스트클래스생성 항목을선택하여테스트클래스를생성한다. BlueJ의클래스또는메소드에대한테스트를실시하기위한첫번째단계는테스트클래스를생성하는것이다. 테스트클래스는프로젝트클래스 ( 참조클래스 (reference class)" 라고부르기로한다 ) 와연관되는클래스로서, 테스트클래스에는참조클래스의메소드를위한테스트가포함된다. 본튜토리얼문서에서는 BlueJ배포판의 examples 디렉토리에포함되어있는 people프로젝트를예제로사용한다. 독자여러분들은 people프로젝트를 BlueJ를오픈하여본튜토리얼문서를읽어보면서조작해보기바란다. 여러분들은컴파일완료된클래스에대하여마우스의오른쪽버튼을클릭하여나타난팝업메뉴의 " 테스트클래스생성 (Create Test Class)" 항목을선택하므로써테스트클래스를생성할수있다. 생성된테스트클래스의이름은테스트대상클래스의이름뒤에 Test" 라는접미어가붙여져서자동으로지정된다. 예를들면, 테스트대상클래스의이름이 Student" 인경우, 생성되는테스트클래스의이름은 StudentTest" 가된다. 테스트클래스는그림1과같이, <<unit test>> 라는태그가붙여진상태로별도의색깔이부여되어, 테스트대상클래스에첨부된형태로화면에나타난다. 테스트대상클래스를드래그하더라도해당테스트클래스또한같이움직임을알수있다. 그림 1 테스트대상클래스와테스트클래스테스트클래스들은 BlueJ환경에서는특별히취급된다. 테스트클래스들은기본적인기능들 ( 열기, 편집, 컴파일, 삭제 ) 뿐만아니라, 테스트와관련된특수기능들 ( 그림2) 을갖는다. 이와같은기능들이활성화되기위해서는테스트클래스가컴파일되어야한다. 테스트클래스자체를생성하는것만으로는어떤테스트도만들어지지않으며, 다만, 테스트 - 6 -
생성에관한선택사항들만을사용자에게제공할뿐이다. 따라서, 테스트클래스는앞으로생성할테스트를보유하려는목적으로사용한다. 그림 2 테스트클래스의팝업메뉴 - 7 -
4. 테스트메소드의생성 요약 테스트클래스의메뉴중에서 테스트메소드생성 (Create Test Method...)" 를선택하여테스트메소드를생성한다. Student클래스의객체들은 2개의메소드, 즉, setname과 getname(person클래스로부터계승 ) 을갖게되며, 각각은학생의이름을지정하거나알아내기위해사용된다. 이러한메소들이정상적으로실행되는지를점검하기위하여테스트를생성해보기를원한다고가정해보자. StudentTest 클래스에대하여 Create Test Method... 항목을선택한다. 테스트메소드는단일테스트를구현하게된다 ( 즉, 1개단일기능에대한테스트를하는것이다 ). 이와같은기능을선택한후에, 해당테스트에대한이름을지정해야한다. 테스트이름은항상 test" 라는접두어를붙여야하며, 이러한규칙을지키지않았을경우에는자동적으로 test" 라는접두어가부여된다. 따라서, testname" 또는 name" 을입력하게되면, testname" 이라는테스트메소드가생성된다. 테스트이름을지정한후에 OK를선택하면, 모든상호작용들이해당테스트내용으로서기록된다. 기록 (recording)" 지시등이 on상태로되고, 해당테스트기록을종료또는취소하기위한버튼이활성화된다.( 그림3) 그림 3 테스트기록을위한테스트버튼들주어진예제에서테스트를기록하기위하여, 다음과같이수행한다 : (1) 매개변수없이생성자를사용하여, Student객체를생성한다. (2)Person클래스로부터계승받은 setname(newname) 메소드를호출하여 "Fred" 라는이름을부여한다. (3)getName() 메소드를호출한다. - 8 -
getname메소드를호출하게되면메소드실행결과를보여주는화면이나타난다. 테스트를기록하는동안, 결과화면에는해당결과에대한검증사항들 (assertions) 을지정할수있는부분이나타난다 ( 그림4). 이와같은검증항목을이용하여해당테스트에대한기대결과를지정할수있다. 해당예제에서는, Fred" 라는문자열이메소드호출에대한기대결과이므로, 이것을검증사항항목에지정하였다 ( 그림4). 그림 4 검증사항 (assertion) 을기입한결과화면 동일성에대한테스트 (tests for equality), null값인지여부등, 다양한형태의검증사항들을지정할수있다. 위의예에서해당테스트케이스가완결되었으므로, 테스트기록을완료하기위하여테스트기록지시자아래에있는 End" 버튼을클릭할수있다. 테스트를종료함으로써, 테스트클래스에해당테스트메소드가추가된다. 이와같은테스트메소드는실행가능한상태가된다. 또한, 테스트기록을종료하기위하여 Cancel" 버튼을누를경우, 테스트기록은폐기된다. 이상에서살펴본예제와유사한방법으로, 독자여러분들은다양한테스트를기록할수있다. 프로젝트내의각클래스들은자기자신을위한테스트클래스를갖출수있으며, 각테스트클래스들은다수의테스트를가질수있다. 각테스트기록들은여러개의액션들로구성될수있으며, 각액션에는여러개의인스턴스생성동작과여러개의검증사항 (assertion) 을포함할수있다. - 9 -
5. 테스트실행 요약 Run Tests" 버튼을클릭하여모든테스트를실행한다. 개별적으로테스트를수행하고자할경우에는테스트클래스의메뉴에서선택하여실행시킨다. 테스트들이기록되면, 실행시킬수있다. 테스트클래스들은참조클래스와같은형태의 Java클래스들이므로, 실행시키기전에컴파일되어야한다. BlueJ에서는각각의테스트들을기록한후에테스트클래스들을자동적으로컴파일할수있다. 검증사항에기입된표현식에에러가포함되었을경우, 또는테스트클래스가수작업에의해작성되었을경우에는, 사전에테스트클래스를반드시컴파일해야한다. 이렇게함으로써이제테스트클래스에대하여마우스오른쪽버튼클릭을하여해당클래스의팝업메뉴에기록된테스트를살펴볼수있게된다. 그림5에는위에서살펴보았던테스트메소드 (testname) 와 2번째테스트 (teststudentid) 에관한예가표시되어있다. 그림 5 2개의테스트메소드가표시된테스트클래스의메뉴위에표시된메뉴에서한개의테스트를선택함으로써개별적으로테스트를수행할수있다. 또한, 테스트클래스의메뉴에있는 Test All" 항목을선택함으로써해당클래스에정의된모든테스트를실행시킬수있다. 개별적으로테스트를수행할경우, 다음과같이두가지경우중, 어느한가지경우가발생할수있다. (1) 테스트가성공 ( 검증사항이모두만족 ) 하는경우, 성공을알리는설명문이윈도우하단에있는프로젝트윈도우상태바에표시된다. (2) 테스트가실패 ( 검증사항이불만족되거나기타다른문제점이발생 ) 하는경우, 테스트결과윈도우에는해당테스트실행결과에대한상세한사항들이표시된다 ( 그림6). - 10 -
만약모든테스트들을실행시켰을경우에는, 테스트결과윈도우에는테스트출력결과가표시된다. 메인윈도우에있는테스트기록지시자상단에있는 Run Tests" 버튼도사용할수있다. Run Tests" 버튼을활성화시키면패키지내의모든테스트클래스들에있는모든테스트를실행시킬수있다. 이와같은방법은해당패키지에대한모든테스트를실행시키는표준적인방법이다. - 11 -
6. 테스트결과에대한해석 요약 테스트결과윈도우에는테스트실행에대한요약과더불어실패한경우의세부사항까지표시된다. 그림 6 테스트결과윈도우테스트가실행되면, 테스트결과윈도우에는테스트결과에대한요약내용이출력된다 ( 그림6). 테스트결과윈도우의상단패널에는실행된모든테스트의목록이성공또는실패를알려주는아이콘과함께표시된다. 녹색마크는성공한테스트를, 회색마크는실패한테스트, 그리고빨간색마크는에러를각각표시한다. 실행테스트와에러그리고실패에대한각각의건수들은테스트결과윈도우의중간부분에요약되어있다. 검증사항중에서만족되지않는것이있을경우, 해당테스트는실패 ( 회색마크 ) 한다. 예를들면, 테스트검증사항이어떤특정한메소드의결과가 null이되면않된다라고규정할수있다. 테스트는에러를포함할수도있다. 테스트를실행한결과, 예상치못한예외처리가발생하는등의에러가발생하는경우가이에해당한다. 성공하지못한테스트에대하여, 테스트목록중에서해당테스트를선택함으로써테스트실패에관한세부사항들을화면에표시할수있다. 테스트결과윈도우의최하단패널에는테스트실패또는에러에관한상세한정보가표시된다. - 12 -
테스트윈도우의중간부분에있는바에는테스트실행에대한주요사항이요약되어표시된다. 즉, 해당바가녹색이되면, 모든테스트가성공했음을표시하는것이고, 빨간색인경우에는적어도한개의테스트가실패하여문제가발생했음을알려준다. MacOS 에서는이와같은바의색깔이변화하지않음에주의하기바란다. - 13 -
7. 설비 (fixture) 란? 요약 테스트설비 (test fixture) 는, 테스트에대한시작지점으로사용되는객체들의집합이다. 때로는테스트를수행할때, 실제테스트를시작하기에앞서몇가지객체들을준비해둘필요가있다. 예를들면, 몇가지테스트를위하여 people' 프로젝트내의 Database클래스에대하여, Database객체와 Student객체그리고 Staff객체등을준비하고, 또한, student 및 staff 멤버를특정한상태 (name과 age값 ) 로설정해둘필요가있다. 독자여러분들은이와같이필요로하는객체들을생성하고이들을적절한상태로설정할수있다. 그러나, 보다세련되게테스트를수행하려면이와같은방식은지루할수도있으므로, 이와같은방식보다더좋은방안을사용할수도있다. 특정한테스트클래스에대한모든테스트를수행하기위한시작점으로서, 특정한상태를갖는객체들을 Object bench에만들어둘수있다. 이와같이테스트를위해서사전에만들어지는객체들의집합을테스트설비 (fixture) 라고부른다. 테스트설비는사전에정의될수있으며, 동일한테스트클래스의모든테스트시작에앞서서자동적으로설정될수있다. 따라서, 각각의개별적인테스트에대한부담을경감시킬수있게된다. - 14 -
8. 테스트설비 (test fixture) 의생성과사용 요약 테스트클래스에대한테스트설비를생성하기위하여, 필요시되는객체들을 object bench에생성하고, 테스트클래스의메뉴중에서 ObjectBench To Test Fixture" 항목을선택한다. 필요시되는객체들을생성하여테스트설비를만들고, 필요한상태를설정하기위하여해당객체에대하여메소드를호출한다. 예를들면, people프로젝트에있는 database클래스를테스트하기위하여, Database객체와 Fred" 라는이름을갖는 Student객체가필요하게된다. "Fred" 라는이름을갖는 Student 객체는 database 에격납시키고, Jane" 이라는이름을갖는 Staff객체는 database 에격납시키지않는다. 이를위하여, 해당객체들을생성시키고 Fred" 를 database 에격납시키기위해필요한메소드호출을수행한다. object bench의상태가현재수행하려는테스트를시작하기에적합하다면, DatabaseTest 클래스의 ObjectBench To Test Fixture" 기능을선택한다. 이와같은기능을선택함으로써 Object Bench 로부터모든객체들이삭제되면서, 해당클래스에대한테스트설비가생성된다. 임의의클래스가테스트설비를갖게되면, 모든테스트의시작시기에해당설비가재생성될것이다. 예를들면, Database클래스에대해 ( 해당테스트클래스의 Create Test Method" 를선택하여 ) 새로운테스트를생성했을경우, 테스트설비에정의된상태가자동적으로재저장된다. 이와같은테스트설비내의객체들은테스트기록을시작할때정의된상태로 Object Bench에나타난다. 또한, 테스트설비상태는테스트클래스의메뉴에있는 Test Fixture To Object Bench" 를선택하므로써 Object Bench에다시생성될수도있다. 이와같이함으로써테스트설비를나중에확장 ( 새로운태스트메소드가테스트설비객체를추가적으로필요로 ) 할때유용하다. 이와같은경우, 테스트설비상태를다시생성하기위하여 Test Fixture To Object Bench" 를사용할수있으며, 수작업에의해설비상태에필요시되는추가사항을기입한다. 이와같은확장작업이종료되면, 테스트설비를저장하기위하여 Object Bench To Test Fixture" 를선택한다. 변경전의테스트설비는새로운것으로바뀌게된다. - 15 -
9. 수작업에의한테스트메소드작성 요약테스트메소드는테스트클래스의소스코드에직접작성해넣을수있다. 사용자와의상호작용과 object bench상태를기록하여테스트메소드들과테스트설비들을생성하는것은단위테스트를작성하는일개수법에불과하다. 또다른방법으로서, 수작업에의해테스트메소드들을작성할수도있다. 테스트클래스는일반프로젝트에있는클래스들과마찬가지로 Java클래스이므로, 같은방식으로취급할수있다. 즉, 소스코드를보기위하여에디터를오픈하여편집할수도있고, 컴파일과실행등을수행할수도있다. JUnit의전통적인사용방법 (BlueJ사용법이아님 ) 에있어서는, 수작업에의한테스트메소드작성법은표준적인방법이며, BlueJ에서도이와같은방법을사용할수있다. 테스트를상호작용방식으로기록하는것은수작업에의한테스트작성방식에추가된내용일뿐, 대체방법이아니다. JUnit에친숙하지않은독자들은, 상호작용방식으로테스트설비와몇가지테스트메소드를작성하여테스트클래스의소스코드를검사하는것이편리할것이다. 각각의테스크클래스들은 setup() 이라는메소드를갖게되며, 이러한 setup() 메소드는테스트설비를구성하는데사용된다는사실에주목하기바란다. 이때, setup() 메소드는각테스트에대한추가적인메소드를갖는다. 기존의테스트메소드에대하여, 수작업으로동작을수정하거나, 완전히새롭게수작업으로테스트메소드를추가하기위하여편집하는것은바람직하다. 특히, 테스트메소드의이름을 test" 라는접두어로시작되게만들어서테스트메소드임을알수있도록해야한다. JUnit테스트작성에관하여보다상세한사항을알아보기위해서는본튜토리얼문서의종반부에있는 JUnit관련참고문헌을읽어보기바란다. - 16 -
10. 테스트를먼저작성하기 요약 구현하기전에테스트를작성하기위해서는, 수작업에의해테스트를작성하거나메소드스터브 (method stub) 를사용해야한다. XP(eXtreme Programming) 기법에의하면, 테스트는메소드를구현하기전에작성되어야한다고한다. BlueJ의단위테스트통합기능을사용함으로써, 다음과같이 2가지방법으로이와같은문제를해결할수있다. 첫번째방법으로서, 앞절에서설명한바와같이, 수작업에의해테스트를작성한다. 테스트를작성하고 JUnit에서설명하고있는구현방식으로작업한다. 두번째방법으로서, 참조클래스내에메소드스터브를작성한다. 이러한메소드스터브의리턴값은임의의값 (dummy value) 으로하되, void형이되어서는않된다. 이와같이작성한후에, 상호작용방식의기록기능을이용하여테스트를생성할수있다. 이때, 완성된구현부분에대한기대결과값에대응하는점검사항을작성하여기입하도록한다. - 17 -
11. 다중클래스테스트 요약 "New Class..." 를이용 ( 단, 클래스유형은 Unit Test" 으로설정 ) 하여비의존적인형태의테스트클래스를생성할수있다. 앞서살펴보았던예제들에서는참조클래스에첨부된형태의테스트클래스가사용되었다. 이와같이테스트클래스를참조클래스에첨부하는방법으로는다른클래스타입에대한테스트에테스트클래스를사용할수없다. 경우에따라서는, 여러개의클래스들을조합하여테스트를수행하도록테스트클래스가작성되어야할경우도있다. 즉, 한개클래스에만논리적으로연관시키지않는형태의테스트클래스를작성할수도있다는것이다. 이를위해서, 테스트클래스들은한개의클래스에만직접첨부되지않도록해야한다. 이를위하여, New Class..." 기능을이용하여독립된형태의테스트클래스를생성할수있으며, 클래스생성시에클래스의유형을 Unit Test" 으로선택해야한다. 독립된형태로만들어진테스트클래스들은기존의테스트클래스들과동일한방법으로사용할수있다. 즉, 테스트설비생성, 테스트메소드작성, 그리고테스트시행등이가능하다. - 18 -
12. 요약 1. BlueJ에서는 JUnit를통합한형태의회귀테스트 (regression testing) 기능을제공한다. 2. 테스트도구들은설정메뉴 (preferences) 에서설정변경을함으로써활성화된다. 3. 클래스의팝업메뉴에서 테스트클래스생성 항목을선택하여테스트클래스를생성한다. 4. 테스트클래스의메뉴중에서 테스트메소드생성 (Create Test Method...)" 를선택하여테스트메소드를생성한다. 5. Run Tests" 버튼을클릭하여모든테스트를실행한다. 개별적으로테스트를수행하고자할경우에는테스트클래스의메뉴에서선택하여실행시킨다. 6. 테스트결과윈도우에는테스트실행에대한요약과더불어실패한경우의세부사항까지표시된다. 7. 테스트설비 (test fixture) 은, 테스트에대한시작지점으로사용되는객체들의집합이다. 8. 테스트클래스에대한테스트설비를생성하기위하여, 필요시되는객체들을 object bench에생성하고, 테스트클래스의메뉴중에서 ObjectBench To Test Fixture" 항목을선택한다. 9. 테스트메소드는테스트클래스의소스코드에직접작성해넣을수있다. 10. 구현하기전에테스트를작성하기위해서는, 수작업에의해테스트를작성하거나메소드스터브 (method stub) 를사용해야한다. 11. "New Class..." 를이용 ( 단, 클래스유형은 Unit Test" 으로설정 ) 하여비의존적인형태의테스트클래스를생성할수있다. - 19 -