<30322DC7C1B7CEC6E4BCC5B3CE5F E687770>
|
|
- 예원 문
- 5 years ago
- Views:
Transcription
1 95 CHAPTER 4 테스트주도개발 제 대로동작할것을이미알고있는상황에서요구사항을충족시키기위한최소한의코드만 작성할수있다면정말멋지지않겠는가? 테스트주도개발 TDD: Test Driven Development 은개발자 가작성하는코드는올바르게동작해야하고, 요구사항을충족해야하며, 유지보수가쉬워야한다는소프트웨어개발에필요한모든것이포함된개념이다. 그이름에서알수있듯이 TDD를학습하다보면여러분의소프트웨어디자인이정확히의도한대로동작한다는것을보장할수있다는사실에놀라게될것이다. TDD의배경이되는개념은단하나이다. 즉, 실제코드를작성하기전에테스트코드를먼저작성하고테스트가실패하는지확인한후테스트에성공할수있도록코드를수정하고정리한다. 그리고이작업을반복하면된다. 이런작업은그림 4-1에서알수있듯이레드, 그린, 리팩토링주문이라고알려지고있다. TDD 방법론에따라코드를작성하려면우선실패하는테스트코드를작성하게된다. 테스트가실패하는이유는실제로배포할기능을구현하는코드가아니기때문이다. 대부분의단위테스트프레임워크는테스트가실패했음을알리기위해붉은색마크를테스트항목옆에표시하며, 이것이 레드 상태를의미하게된다. 테스트에실패하면여러분은테스트를통과할수있는최소한의코드를작성하여테스트를다시실행한다. 역시대부분의테스트프레임워크는테스트가성공했음을알리기위해녹색마크를표시한다. 이상태가바로 그린 상태이다. 이제리팩토링과정에서는코드를정리하고, 중복코드를제거하며, 유지보수가용이하도록코드를단순화하는과정을거치게되는데, 이미테스트는성공했기때문에리팩토링을실시해도좋은상태이며, 모듈의외부동작이아니라내부동작을수정할뿐이므로곧바로배포가가능한코드를구현할수
2 96 CHAPTER 4 테스트주도개발 있게된다. TDD 방법론을도입하면매우짧은주기로코딩작업을할수있으며, 이시점에여러분이작성하는프로그램에는단하나의요구사항만이존재하게된다. 간단한테스트코드를작성하고테스트를통과하기위한최소한의코드만작성한후리팩토링하고이과정을계속해서반복한다. 작은단위로작업을반복하는아이디어가바로핵심이며, 이로인해여러분은작고간결하며느슨하게결합된코드모듈을작성할수있게된다. 모든테스트를통과하게되면여러분의작업이완료되는것이며, 여러분의소프트웨어가의도된대로동작하는것을확인할수있는완벽한테스트코드들을갖추게된다. 리팩토링과정에서코드의동작이변경되지않았는지확인한다. 레드 실패하는테스트코드를작성한다. 리팩토링 그린 코드의중복을제거하여단순화한다. 테스트를통과하는코드를작성한다. 그림 4-1 지금쯤여러분은 TDD가매우현명한방법이라고생각하거나, 아니면존재하지도않는코드를위한테스트코드를작성하는것이어떻게소프트웨어의디자인에도움이되며소프트웨어의배포주기를향상시킬수있는지를알아내기위해머리를쥐어뜯고있을것이다. TDD가어떤이점을제공하는지를학습하기위해더많은내용들을읽어보는것도좋지만간단한 TDD 예제를실행해보는것이더좋을것이다. 이예제는 TDD가제공하는다른이점들에대해읽어보기전에전체적인프로세스를이해하는데도움이될것이다.
3 TDD 예제 : 틱택토게임 97 TDD 예제 : 틱택토게임 이제여러분은일명 3목두기라고알려진틱택토 Tic Tac Toe 게임을플레이할수있는프로그램을만들것이다. 이예제를통해여러분은 TDD가정확히무엇이며, 이것이애플리케이션디자인에어떤영향을미치는지학습하게될것이다. 프로그램을작성하기에앞서우선게임의규칙을이해하는것이중요하다. 특히이게임을해본적이없거나들어본적이없다면더욱중요하다. 틱택토는두사람이플레이할수있는간단한게임이다. 첫번째플레이어는 X로표시하며, 두번째플레이어는 O로표시한다. 틱택토게임의목적은 3행 3열로구성된보드에상대방보다먼저한줄을채우는것이다. 플레이어 X가항상먼저시작하며, 둘중한사람이한행이나한열혹은대각선방향으로자신의표시세개를나란히채우거나혹은보드에더이상표시를할수없을때까지교대로 X와 O를채워나가게된다. 9개의공간을모두채웠지만누구도자신의표시세개를나란히채우지못한경우에는게임은무승부가된다. TDD를연습하기전에요구사항의목록을작성해보거나혹은구현하고자하는애플리케이션의사용자시나리오를구성해보는것이좋다. 틱택토게임의요구사항 게임은 3행 3열로구성된보드에서진행된다. 게임은두명의플레이어가진행하며각각 X 표시와 O 표시를사용한다. 각각의플레이어는빈공간에자신의순서가되면표시를한다. 둘중한플레이어가한줄에세개의표시를나란히배치하면승리하게된다. 이한줄은한행이나한열혹은대각선이될수도있다. 모든공간이다채워졌으며승자가없다면게임은무승부가된다. TDD의관점에서요구사항목록만가지고는좋은단위테스트를구성할수없다. 단위테스트는일반적인요구사항보다는조금더구체적인내용을요구한다. 각각의테스트는의도된동작과알려진입력에대한특정한출력의예를표현할수있어야한다. 이요구사항을테스트를토대로다시정리해보자. 이기본적인테스트들은프로그램을구현해나가면서점차늘어나게되며작업을진행해나감에따라더많은테스트가필요해질것이분명하기때문에언제든지목록에추가하면된다.
4 98 CHAPTER 4 테스트주도개발 기본적인테스트먼저플레이를시작하는플레이어는 X이다. 플레이어는이미채워진공간에는표시를할수없다. 플레이어 X가빈공간에 X 표시를하면이공간은더이상사용할수없다. 플레이어 O는플레이어 X가표시를한후에표시할수있다. 플레이어는존재하지않는공간에는표시할수없다. 이미사용된공간에표시를하려고하면예외가발생한다. 플레이어 X가한행에세개의 X 표시를모두하면플레이어 X가승리한다. 플레이어 X가한열에세개의 X 표시를모두하면플레이어 X가승리한다. 플레이어 X가대각선으로세개의 X 표시를모두하면플레이어 X가승리한다. 모든공간이채워지고승자가없으면게임은무승부가된다. 우선첫번째테스트코드를작성하기에앞서우선프로젝트를준비해야한다. 이예에서는 NUnit 테스트프레임워크를사용하기로하자. 1. 우선 NUnit 프레임워크의최신버전을다운로드하자. 이글을작성하는시점의가장최신버전은 NUnit 2.4.8이다 ( 옮긴이 _ 이글을번역하는시점의 가장최신버전은 이다. 그러나예제를구현하기에는아무런차이가없다 ). 2. 프레임워크를다운로드했으면 MSI 인스톨파일을실행한다. NUnit이설치되고나면 Program Files 폴더에새폴더가생성될것이다. 이제 NUnit 프레임워크의설치를완료했으므로테스트코드의작성을시작해보자. 1. Visual Studio를실행하고그림 4-2와같이 C:\Projects 디렉터리에 ProEnt.Chap4라는이름의빈솔루션을생성한다. 2. 다음의절차를따라솔루션에클래스라이브러리프로젝트를추가한다. 1. 파일메뉴에서 [ 추가 새프로젝트 ] 메뉴를선택한다. 2. 클래스라이브러리프로젝트템플릿을선택한다. 3. 프로젝트의이름을 ProEnt.Chap4.TicTacToe.Model로지정한다. 3. 동일한방식으로두번째클래스라이브러리프로젝트를 ProEnt.Chap4.TictacToe.ModelTests 라는이름으로추가한다.
5 TDD 예제 : 틱택토게임 99 그림 모든프로젝트를추가했으면솔루션아이템을마우스오른쪽버튼으로클릭한후 [Windows 탐색기에서폴더열기 ] 메뉴를선택한후 lib라는이름의폴더를추가하고 NUnit.Frame work.dll 파일을 NUnit 프레임워크가설치된디렉터리에서복사한다 ( 이경로는기본적으로 %systemdrive%\%programfiles directory%\nunit 2.4.8\bin 폴더이다 ). 5. 이제솔루션에 Lib라는새로운솔루션폴더를추가한다. 그러려면솔루션아이템을마우스오른쪽버튼으로클릭한후 [ 추가 새솔루션폴더 ] 메뉴를선택한다. 6. 새로추가한 Lib 폴더를마우스오른쪽버튼으로클릭하고 [ 추가 기존항목 ] 메뉴를클릭한후애플리케이션의루트에생성했던 lib 폴더에있는 NUnit.Framework.dll 파일을선택한다. ProEnt.Chap4.TicTacToe.ModelTests 프로젝트를마우스오른쪽버튼으로클릭하고 [ 참조추가 ] 메뉴를선택하여 ProEnt.Chap4.TicTacToe.ModelTests 프로젝트에 NUnit. Framework.dll 파일을추가한다. 새참조추가대화상자에서 [ 찾아보기 ] 탭을선택하여 Lib 폴더를탐색한후 NUnit.Framework.dll 파일을선택하고 [ 참조추가 ] 버튼을클릭하면된다.
6 100 CHAPTER 4 테스트주도개발 7. 마지막으로 ProEnt.Chap4.TicTacToe.Model 프로젝트를마우스오른쪽버튼으로클릭하고 [ 참조추가 ] 메뉴를클릭하여 ProEnt.Chap4.TicTacToe.ModelTests 프로젝트에대한참조를추가한다. 참조추가대화상자에서 [ 프로젝트 ] 탭을선택하고 ProEnt.Chap4. TicTacToe.Model 프로젝트를선택한다. 지금까지의과정을마친후의솔루션탐색기의모습은그림 4-3과같다. 그림 4-3 ProEnt.Chap4.ticTacToe.ModelTests 프로젝트에 SimpleTest라는이름의클래스를생성하고다음의코드를작성한다. using System; using NUnit.Framework; namespace ProEnt.Chap4.TicTacToe.ModelTests [TestFixture()] public class SimpleTest
7 TDD 예제 : 틱택토게임 101 [Test()] public void My_First_NUnit_Test() int expectedresult = 3; Assert.AreEqual(expectedResult, 1 + 1); SimpleTest 클래스에 [TestFixture] 특성을지정하면이클래스가테스트코드를갖추고있음을 NUnit 프레임워크에알려주는셈이된다. 테스트메서드들은항상 public 메서드여야하며, 매개변수와리턴값이없어야하고, [Test] 특성이지정되어있어야한다. Assert 클래스가제공하는 static 메서드들은다양한방법으로현재의상태가올바른지를검증하기위해사용된다. AreEqual 메서드는테스트를통해기대하는값과실제값이동일한지를비교한다. 프로젝트를빌드하고시작메뉴에서 NUnit 애플리케이션을클릭하여실행한후 Program Files 폴더의 NUnit 폴더를열어보자. NUnit 애플리케이션에서 [File Open Project] 메뉴를선택한후 ProEnt.Chap4.TicTacToe.ModelTests 프로젝트의 Debug 폴더를탐색하여 ProEnt.Chap4.TicTacToe.ModelTests.dll 파일을선택한다. ProEnt.Chap4.TicTacToe.ModelTests. dll 파일이열리면그림 4-4와같은테스트트리를볼수있을것이다. 그림 4-4
8 102 CHAPTER 4 테스트주도개발 이제그림 4-5 와같이 Run 버튼을클릭하자. 그림 4-5 테스트결과 3이출력되기를원했지만실제결과는 2가출력되었기때문에테스트는당연히실패할것이다. VisualStudio로되돌아가코드를다음과같이수정하자. using System; using NUnit.Framework; namespace ProEnt.Chap4.TicTacToe.ModelTests [TestFixture()] public class SimpleTest [Test()] public void My_First_NUnit_Test() int expectedresult = 3; Assert.AreEqual(expectedResult, 2 + 1); 프로젝트를다시빌드하고그림 4-6 과같이테스트를다시실행하자.
9 TDD 예제 : 틱택토게임 103 그림 4-6 이제코드는테스트를통과하며녹색신호가나타나는것을볼수있다. 이장의후반부에서여러분은사용가능한다른테스트프레임워크와 NUnit과함께 Visual Studio에통합하여사용할수있는프로그램에대해학습하게될것이다. 이제 NUnit 프레임워크를사용하는방법에대해간략하게살펴보았으므로 TDD 방법론을토대로틱택토게임을구현해보도록하자. 앞서구성했던테스트목록중첫번째테스트는 먼저플레이하는플레이어는 X이다 이므로이것을테스트의제목으로사용할수있다. 테스트의이름을서술적으로표기하여이테스트가어떤내용을테스트하는지쉽게알아볼수있도록하는것이좋으며, 특히테스트항목이늘어나는경우에는이런방법이더욱유용하다. 테스트의이름을지정할때사용할수있는좋은방법은우선무엇을테스트할것인지를나열한후다음으로어떤동작을하는지를나열하는것이다. 바로 먼저플레이하는플레이어는 X이다 라는문장이테스트의제목으로적당하다. 테스트를작성할때프로그램을위한 API를간단하고유연하게작성할수있다. 여러분이구현이완료된소프트웨어를사용할사용자라고가정해보라. 이프로그램을어떻게사용할것인가? 여러분은소프트웨어를위한완벽한인터페이스를제공해야하는위치에있으므로테스트를작성할때는가급적간단하고논리적으로구현해야한다는것을항상염두에두어야하며, 그렇게함으로써소프트웨어에서유용하게활용될수있는코드를작성하게된다. 그러면틱택토게임의모든규칙을확인하기위한테스트코드를작성할클래스를생성해보자. ProEnt.Chap4. TicTacToe.ModelTests 프로젝트에 TicTacToeGameTests라는이름의클래스를생성한다.
10 104 CHAPTER 4 테스트주도개발 앞서설명했던대로첫번째테스트메서드의이름은 Player_X_Is_The_First_To_Place_ A_Marker 라고지정하고다음의코드를작성한다. using System; using NUnit.Framework; using ProEnt.Chap4.TicTacToe.Model; namespace ProEnt.Chap4.TicTacToe.ModelTests [TestFixture] public class TicTacToeGameTests [Test] public void Player_X_Is_The_First_To_Place_A_Marker() TicTacToeGame agameoftictactoe = new TicTacToeGame(); Assert.AreEqual(player.x, agameoftictactoe.whoseturn()); 여러분은코드를컴파일하지는않았지만이미소프트웨어의디자인에있어몇가지큰결정을내린셈이다. 여러분은플레이어의 ID를열거자로표현하도록결정했으며, 메서드가현재순서가된플레이어의 ID를리턴하도록정의했다. 또한 TicTacToeGame 객체의새인스턴스가생성될때게임이시작되도록결정했다. 이런모든결정들은소프트웨어가이미구현이됐다면이소프트웨어를사용할사람의입장에서결정된것이다. 이렇게함으로써 API 자체를쉽게사용할수있도록구성할수있다. 물론방금작성한테스트는컴파일되지않을것이므로약간의코드를더추가하여테스트를컴파일할수있도록한후실패하도록만들어야한다. 지금은실제동작하는코드를작성하기에앞서테스트코드를작성하려는것이기때문에이테스트가실패하도록구현하는것이현재로는가장중요하다. 테스트를컴파일하려면 TicTacToeGame 클래스의뼈대코드와플레이어 X를정의하기위한열거자를구현해야한다. 이제 Player라는이름의열거자와 TicTacToeGame 클래스를다음과같이구현한다. namespace ProEnt.Chap4.TicTacToe.Model public class TicTacToeGame
11 TDD 예제 : 틱택토게임 105 public TicTacToeGame() public player WhoseTurn() return player.o; namespace ProEnt.Chap4.TicTacToe.Model public enum player x = 1, o = 2 기억할것은여러분의코드가테스트를통과하기전에우선실패하는테스트를만들어야한다는점이기때문에 WhoseTurn() 메서드가 player.x를리턴하도록수정하고싶더라도일단은참아야한다. 프로젝트를컴파일하고테스트를수행하면그림 4-7과같이테스트가실패하게된다. 바로이것이우리가원하는결과이다. 이제테스트가성공할수있도록코드를수정해보자. 그림 4-7
12 106 CHAPTER 4 테스트주도개발 이제 WhoseTurn() 메서드가 player.x를리턴하도록수정하자. 테스트프로젝트를다시빌드하고 NUnit 테스트프로그램에서다시테스트하면그림 4-8과같이테스트가성공하게된다. namespace ProEnt.Chap4.TicTacToe.Model public class TicTacToeGame public TicTacToeGame() public player WhoseTurn() return player.x; 그림 4-8 이시점에서여러분은게임이진행되는동안 WhoseTurn() 메서드가항상플레이어 X를리턴할수없기때문에방금작성한테스트코드가올바른것이아니라고생각할수있다. 물론여러분이맞다. 그러나어떤일이일어날지혹은소프트웨어가어떤일을해야하는지에대해고민할필요는없다. 여러분이지금해야하는일은최대한간단한방법으로코드가테스트를통과할
13 TDD 예제 : 틱택토게임 107 수있도록구현하는것이므로다음단계로진행해보자. 새로운테스트가필요하다고생각된다면테스트목록에추가하고작업을계속하자. 이때테스트에필요치않은기능을구현하려고시도하지말자. 여러분은조금씩앞으로나아가야한다. 이예제를구현해나가면서이간단한예제가무엇을보여주고싶어하는지알수있게될것이므로조금만참아보도록하자. 지금까지는매우간단한코드를작성했으므로리팩토링할것도없으므로곧바로다음테스트를진행한다. 처음에작성했던테스트목록을살펴보면다음테스트는 플레이어는이미채워진공간에는표시를할수없다 이다. 이에대해생각해보면 첫번째플레이어는어디에든표시할수있다 라는점에대해테스트를수행하는것이더좋은생각일것이다. 따라서 첫번째플레이어는어디에든표시할수있다 라는테스트를다음과같이추가한다. [Test] public void The_First_Player_Can_Place_Marker_Anywhere() TicTacToeGame agameoftictactoe = new TicTacToeGame(); Assert.IsTrue(aGameOfTicTacToe.CanPlaceMarkerAt(0, 0)); Assert.IsTrue(aGameOfTicTacToe.CanPlaceMarkerAt(0, 1)); Assert.IsTrue(aGameOfTicTacToe.CanPlaceMarkerAt(0, 2)); Assert.IsTrue(aGameOfTicTacToe.CanPlaceMarkerAt(1, 0)); Assert.IsTrue(aGameOfTicTacToe.CanPlaceMarkerAt(1, 1)); Assert.IsTrue(aGameOfTicTacToe.CanPlaceMarkerAt(1, 2)); Assert.IsTrue(aGameOfTicTacToe.CanPlaceMarkerAt(2, 0)); Assert.IsTrue(aGameOfTicTacToe.CanPlaceMarkerAt(2, 1)); Assert.IsTrue(aGameOfTicTacToe.CanPlaceMarkerAt(2, 2)); 흠, 지금작성한코드와디자인에대해별다른이상한낌새는없는가? 게임에사용된보드가 0부터시작하는인덱스로구성되었다는것은좋은생각일까? 또한첫번째정수는행을의미할까아니면열을의미할까? 이코드를사용한다면직접사용해보고에러가발생해야제대로된사용법을배울수있다. 그렇다면여러분의의도를충분히표현할수있게코드를작성해야하지않을까? 이제이코드를쉽게이해할수있도록다시작성해보자. [Test] public void The_First_Player_Can_Place_Marker_Anywhere() TicTacToeGame agameoftictactoe = new TicTacToeGame(); Assert.IsTrue(aGameOfTicTacToe.CanPlaceMarkerAt(Row.One,
14 108 CHAPTER 4 테스트주도개발 Column.One)); Assert.IsTrue(aGameOfTicTacToe.CanPlaceMarkerAt(Row.One, Column.Two)); Assert.IsTrue(aGameOfTicTacToe.CanPlaceMarkerAt(Row.One, Column.Three)); Assert.IsTrue(aGameOfTicTacToe.CanPlaceMarkerAt(Row.Two, Column.One)); Assert.IsTrue(aGameOfTicTacToe.CanPlaceMarkerAt(Row.Two, Column.Two)); Assert.IsTrue(aGameOfTicTacToe.CanPlaceMarkerAt(Row.Two, Column.Three)); Assert.IsTrue(aGameOfTicTacToe.CanPlaceMarkerAt(Row.Three, Column.One)); Assert.IsTrue(aGameOfTicTacToe.CanPlaceMarkerAt(Row.Three, Column.Two)); Assert.IsTrue(aGameOfTicTacToe.CanPlaceMarkerAt(Row.Three, Column.Three)); 이코드는훨씬가독성이높다. 그렇지않은가? 리팩토링은아주간단했지만어떤매개변수가무엇인지정확히의미하며, 다른개발자가보드의인덱스가 0부터시작하는지아닌지추측할필요가없도록해준다. 이테스트는마찬가지로컴파일되지않을것이므로먼저해야할일은컴파일을방해하는요소들을정리하는것이다. 우선 Column과 Row라는두가지열거자클래스를생성한후다음과같이코드를작성한다. namespace ProEnt.Chap4.TicTacToe.Model public enum Column One = 0, Two = 1, Three = 2 namespace ProEnt.Chap4.TicTacToe.Model public enum Row One = 0, Two = 1,
15 TDD 예제 : 틱택토게임 109 Three = 2 두개의열거자를새로추가했으면 TicTacToeGame 클래스의메서드를다음과같이수정하여테스트가컴파일되도록하자. namespace ProEnt.Chap4.TicTacToe.Model public class TicTacToeGame public TicTacToeGame() public player WhoseTurn() return player.x; public bool CanPlaceMarkerAt(Row row, Column column) return false; 다시말하지만, 우선은테스트가컴파일되어도성공하지못하도록해야하므로, CanPlace MarkerAt 메서드가 false를리턴하도록하드코딩된것이다소이해하기는어렵더라도현재로서는우리가원하는결과이다. 모델프로젝트를다시빌드하면테스트는컴파일될것이며, 테스트를실행하면실패하게된다. 이것이바로우리가원했던결과이다. 이제최소한의코드변경으로테스트가성공하도록수정해보자. 테스트가성공할수있는가장간단한방법은하드코딩된 false 리턴값을 true로변경하는것이다. 우선다음과같이코드를변경해보자. namespace ProEnt.Chap4.TicTacToe.Model public class TicTacToeGame public TicTacToeGame()
16 110 CHAPTER 4 테스트주도개발 public player WhoseTurn() return player.x; public bool CanPlaceMarkerAt(Row row, Column column) return true; 테스트를다시실행하면이번에는테스트에성공할것이다. 지금여러분은 TDD의장점에대해알게되기는커녕시간만낭비했다고생각할지도모르겠다. 그러나이예제를통해여러분이학습한것은소프트웨어가올바른동작을수행하는지확인하기위한테스트코드를작성해야한다는것이다. 지금까지처음두개의테스트를통과하기위한코드를작성했다. 앞으로도여러분이작성하는코드가최초의테스트목록을통과할수있는지를확인하기위한테스트들을추가하게될것이다. 이런과정을테스트측정이라고한다. 측정 triangulation 이란, 여러개의서로다른테스트를작성하여다양한관점에서테스트가성공하는지를확인하는과정을말한다. 다시말하면, WhoseTurn 메서드와 CanPlaceMarkerAt 메서드가올바르게동작하는지를확인하기위한또다른테스트코드를작성해야한다는뜻이다. 이제다음테스트는 플레이어 X 가빈공간에 X 표시를하면이공간은더이상사용할수없다 라는항목이다. [Test] public void After_A_Player_Places_A_Marker_The_Square_Is_Unavailable() Row rowtoplace = Row.One; Column columntoplace = Column.One; TicTacToeGame agameoftictactoe = new TicTacToeGame(); agameoftictactoe.placemarkerat(rowtoplace, columntoplace); Assert.IsFalse(aGameOfTicTacToe.CanPlaceMarkerAt(rowToPlace, columntoplace));
17 TDD 예제 : 틱택토게임 111 이전테스트와마찬가지로아직 PlaceMarkerAt 메서드를작성하지않았기때문에테스트를컴파일하려면이메서드부터구현해야한다. 테스트프로젝트가참조하고있는 TicTacToeGame 클래스에 PlaceMarkerAt 메서드를추가하고다음의코드를작성한후 Model 프로젝트를다시빌드한다. namespace ProEnt.Chap4.TicTacToe.Model public class TicTacToeGame public TicTacToeGame() public player WhoseTurn() return player.x; public bool CanPlaceMarkerAt(Row row, Column column) return false; public void PlaceMarkerAt(Row row, Column column) 아마도이코드를컴파일하고테스트를실행하면분명실패할것이라고예상할것이다. 그러면테스트에성공하도록코드를작성해보자. 테스트코드는코드의동작을확인하기위해 TicTacToeGame 클래스의두개의메서드를사용하고있으므로이두메서드를모두수정해야한다. 그러나완전히새로게임을시작했을때 CanPlaceMarkerAt 메서드의동작을확인하기위한테스트메서드가이미존재하므로이메서드는이제 false만을리턴하도록하드코딩되어서는안되며, 이제는게임보드에존재하는각공간의상태를관리해야한다. 그러려면 3행 3열의게임보드를표현할다차원배열을생성해야한다. 지금해야할일은테스트코드를측정하여코드의동작을확인하기위한하나의테스트에만의존하지않도록하는것이다. 보다자세한내용은다음에다시살펴보도록하자.
18 112 CHAPTER 4 테스트주도개발 어쨌든지금은 TicTacToeGame 클래스를다음과같이수정하자. namespace ProEnt.Chap4.TicTacToe.Model public class TicTacToeGame private int[,] Board = new int[3, 3]; public TicTacToeGame() public player WhoseTurn() return player.x; public bool CanPlaceMarkerAt(Row row, Column column) return this.board[(int)row, (int)column] == 0; public void PlaceMarkerAt(Row row, Column column) this.board[(int)row, (int)column] = (int)whoseturn(); 단세줄의코드를추가했을뿐이지만이전의코드와비교해보면큰폭으로달라진것을알수있다. 첫번째는 3행 3열의게임보드에표시된값을관리하기위해다차원배열을생성한것이다. 그런후 CanPlaceMarkerAt 메서드를수정하여전달된값을정수로변환하여주어진위치의값이 0인지를비교하는데, 이경우해당위치에표시가있다는뜻일까? 마지막으로 PlaceMarkerAt 메서드에지정된위치에 WhoseTurn 메서드가리턴한값을대입한다. 이코드를컴파일하고지금까지작성한세개의테스트를모두수행해보면코드가수정되었기때문에이전테스트도순조롭게통과하는것을볼수있을것이다. 이때변경한코드가전체테스트에영향을미치지않는지를확인하기위해모든테스트를실행해보는것이중요하다. 모든테스트를실행하고모두테스트에통과한다면다행이다. 이렇듯 TDD를이용하면변경된코드가다른부분에영향을미치는지여부를즉시알수있게된다.
19 TDD 예제 : 틱택토게임 113 코드를살펴보면알겠지만, CanPlaceMarkerAt 메서드가 false를리턴할경우플레이어가원하는위치에표시할수없도록하는방법은없다. 이런현상을방지하기위해코드를추가로작성할수는있겠지만우선은테스트를먼저작성한후에이동작을수행하는것이더좋다. 다시한번말하지만여러분은테스트를통과하기위한코드만을작성해야한다. 그렇다면이를위한테스트코드를작성해보자. 플레이어가원하는위치에표시를할수있는지를검사하는메서드가이미존재하기때문에사용자가이를무시하려하면프로그램이예외를발생시키는것이논리적이다. 따라서 TicTacToeGameTests 클래스에새로운테스트를다음과같이추가하여문제가되는상황에서코드가적절히동작하는지확인해보자. [Test] [ExpectedException(typeof(System.ApplicationException), "Square Row:One, Column:One already occupied by x" )] public void Exception_Will_Be_Thrown_If_Player_Tries_To_Place_Marker_In_A_Taken_Square() Row rowtoplace = Row.One; Column columntoplace = Column.One; TicTacToeGame agameoftictactoe = new TicTacToeGame(); agameoftictactoe.placemarkerat(rowtoplace, columntoplace); agameoftictactoe.placemarkerat(rowtoplace, columntoplace); 이테스트는지금까지작성했던것과는조금다르다. 이테스트메서드는두번째특성이지정되어있으며, 입력값에대한유효성검사를수행하는코드는없다. 이메서드에지정된 Expected Exception 특성은 NUnit 프레임워크가지정된메시지를가진예외가발생하는경우에테스트를통과한것으로처리하도록하기위한것이다. 테스트를실행해보면실패하게된다. 이제플레이어가표시하려고하는공간이실제로비어있는지를검사하여비어있지않다면적당한예외를발생시키는코드를추가하자. 수정된 Place MarkerAt 메서드의코드는다음과같다. namespace ProEnt.Chap4.TicTacToe.Model public class TicTacToeGame private int[,] Board = new int[3, 3]; public TicTacToeGame()
20 114 CHAPTER 4 테스트주도개발 public player WhoseTurn() return player.x; public bool CanPlaceMarkerAt(Row row, Column column) return this.board[(int)row, (int)column] == 0; public void PlaceMarkerAt(Row row, Column column) if (CanPlaceMarkerAt(row, column)) this.board[(int)row, (int)column] = (int)whoseturn(); else throw new ApplicationException( string.format("square Row:0, Column:1 already occupied by 2", row.tostring(), column.tostring(), (player)enum.toobject(typeof(player), this.board[(int)row, (int)column]))); TDD의규칙을곧이곧대로해석한다면여러분은테스트를통과할수있는가장간단한코드를작성하려할것이며, 따라서 CanPlaceMarkerAt 메서드를다음과같이작성할것이다. namespace ProEnt.Chap4.TicTacToe.Model public class TicTacToeGame... public void PlaceMarkerAt(Row row, Column column) if (CanPlaceMarkerAt(row, column))
21 TDD 예제 : 틱택토게임 115 this.board[(int)row, (int)column] = (int)whoseturn(); else throw new ApplicationException( "Square Row:One, Column:One already occupied by x") 그러나알다시피이예외의에러메시지에는문제가발생한행과열번호를동적으로삽입할필요가있으므로, 순수한의미의 TDD와비교해약간의절충안을취하여다시실용적인관점에서접근할수있다. 하지만그럼에도불구하고여러분은계속해서조금씩단계를밟아나가야하며, 결코걷기전에뛰려고하거나혹은하나의테스트에서너무많은작업을하려고해서는안된다. 여러분은테스트에성공할수있는코드를작성하려는것이지전체프로그램을작성하려는것이아님을다시한번기억하기바란다. 다시말하면, 우선규칙을이해해야무엇을할지알수있게되며, 그런후에야작업속도를올릴수있게된다. 지금필자가바라는것은여러분이지금처럼 TDD의규칙을약간어김으로써얻을수있는이점이무엇인지를파악하는것이다. 여러분은테스트를통과하기위한최소한의코드를작성한것은아니지만그렇다고해서디자인전체를복잡하게하지도않았다. 여러분은행과열의조합이언제든지변경될수있다는것을알기때문에나중에이전테스트코드가동작하지않게될경우, 필요한또다른테스트코드를작성하는대신이를처리할수있도록테스트코드를작성하겠다는주관적인판단을내린것뿐이다. 이런과정은순수하게학술적인 TDD에대한접근법에는다소어긋난것이지만이번에사용한방법은상식적인면에서크게벗어나지않는다. TDD에대해더많이경험하다보면시스템이테스트를필요로하지않는부분이어떤부분인지혹은어디쯤에서규칙을약간어겨도무방한지를명확하게판단할수있게될것이다. 이섹션의나머지부분들은지금경험한내용을토대로한다. 이제여러분이방금무슨일을했는지이해했으므로틱택토게임의나머지기능들을계속해서구현해보자. 테스트목록으로돌아가보면다음테스트항목은 플레이어 O는플레이어 X가표시를한후에표시할수있다 이다. 이테스트는 WhoseTurn 메서드가올바르게동작하지않는다는점을밝혀내기위한것이다. 이런방법은이미테스트가완료되었다고생각한부분을다시한번확인하는좋은방법이다. 그러면 TicTacToeGameTests 클래스에다음의테스트메서드를추가해보자.
22 116 CHAPTER 4 테스트주도개발 [Test] public void Player_O_Will_Be_Next_To_Take_A_Turn_After_Player_X_Has_Placed_A_ Marker() Row rowtoplace = Row.One; Column columntoplace = Column.One; TicTacToeGame agameoftictactoe = new TicTacToeGame(); Assert.AreEqual(player.x, agameoftictactoe.whoseturn()); agameoftictactoe.placemarkerat(rowtoplace, columntoplace); Assert.AreEqual(player.o, agameoftictactoe.whoseturn()); 이제테스트를실행해보면테스트가실패하는것을볼수있는데, 그이유는 WhoseTurn() 메서드가앞서작성했던테스트를성공하기위해항상 player.x를리턴하도록하드코딩되어있기때문이다. 이제이코드를리팩토링하여현재보드에표시를할수있는실제플레이어를리턴하도록수정해보자. 그러려면현재플레이어를보관할변수를추가하고, 생성자에서이변수에플레이어 X를지정한후플레이어 X가보드에표시를하면다른플레이어로변경하면된다. 다음의코드는현재플레이어를표시하기위해수정된코드를표시하고있다. namespace ProEnt.Chap4.TicTacToe.Model public class TicTacToeGame private int[,] Board = new int[3, 3]; private player currentplayer; public TicTacToeGame() currentplayer = player.x; public player WhoseTurn() return currentplayer; public bool CanPlaceMarkerAt(Row row, Column column) return this.board[(int)row, (int)column] == 0;
23 TDD 예제 : 틱택토게임 117 public void PlaceMarkerAt(Row row, Column column) if (CanPlaceMarkerAt(row, column)) this.board[(int) row, (int) column] = (int) WhoseTurn(); if (this.currentplayer == player.x) this.currentplayer = player.o; else this.currentplayer = player.x; else throw new ApplicationException( string.format( "Square Row:0, Column:1 already occupied by 2", row.tostring(), column.tostring(), (player)enum.toobject(typeof(player), this.board[(int)row, (int)column]))); 이제모든테스트를실행해보면테스트가모두통과한다는것을알수있다. 그런데 Place MarkerAt 메서드의코드가점점늘어나고있다. 이때여러분은현재플레이어를변경하는로직을별도의메서드로리팩토링하여코드를더욱읽기쉽게만들수있다. 현재플레이어를검사하여플레이어를변경하는부분의로직을선택하고오른쪽버튼을클릭한후 [ 리팩토링 메서드추출 ] 메뉴를선택한다. 메서드추출대화상자에서는새로추가할메서드의이름을 Change CurrentPlayer라고입력한다. 변경된코드는다음과같다. namespace ProEnt.Chap4.TicTacToe.Model public class TicTacToeGame... public void PlaceMarkerAt(Row row, Column column)
24 118 CHAPTER 4 테스트주도개발 if (CanPlaceMarkerAt(row, column)) this.board[(int) row, (int) column] = (int) WhoseTurn(); ChangeCurrentPlayer(); else throw new ApplicationException( string.format( "Square Row:0, Column:1 already occupied by 2", row.tostring(), column.tostring(), (player)enum.toobject(typeof(player), this.board[(int)row, (int)column]))); private void ChangeCurrentPlayer() if (this.currentplayer == player.x) this.currentplayer = player.o; else this.currentplayer = player.x; 이제다시한번모든테스트를실행하여조금전실행했던리팩토링으로인해영향을받은부분이없는지확인하자. 다음으로구현할테스트항목은 플레이어는존재하지않는공간에는표시할수없다 라는항목이다. 이동작을검증할테스트를다음과같이작성하면이테스트는컴파일에실패하게된다. [Test] public void A_Player_Cannot_Place_A_Marker_In_A_Zone_That_Does_Not_Exist() TicTacToeGame agameoftictactoe = new TicTacToeGame(); Assert.IsFalse(aGameOfTicTacToe.CanPlaceMarkerAt(33, 11));
25 TDD 예제 : 틱택토게임 119 이코드가컴파일이되지않는이유는여러분이 row와 column 변수값을위해열거자를사용하기로했기때문이며, 이부분은처음에테스트목록을구성할때고려되지않았던것이다. 이와같은디자인결정으로인해사용자들은오직유효한행과열위치를표시하는값만을사용할수있음이검증되었으므로이테스트코드는주석으로처리하고다음테스트를진행하도록하자. //[Test] //public void A_Player_Cannot_Place_A_Marker_In_A_Zone_That_Does_Not_Exist() // // TicTacToeGame agameoftictactoe = new TicTacToeGame(); // Assert.IsFalse(aGameOfTicTacToe.CanPlaceMarkerAt(33, 11)); // 다음테스트는게임의승자를가려내기위한것으로 플레이어 X가한행에세개의 X 표시를모두하면플레이어 X가승리한다 라는항목이다. [Test] public void If_Player_X_Gets_Three_Xs_In_A_Row_Then_The_Game_Is_Won_By_Player_X() Row PlayerX_RowMove123 = Row.One; Column PlayerX_ColumnMove1 = Column.One; Column PlayerX_ColumnMove2 = Column.Two; Column PlayerX_ColumnMove3 = Column.Three; Row PlayerO_RowMove12 = Row.Two; Column PlayerO_ColumnMove1 = Column.One; Column PlayerO_ColumnMove2 = Column.Two; TicTacToeGame agameoftictactoe = new TicTacToeGame(); // Player X Move 1 // X // // agameoftictactoe.placemarkerat(playerx_rowmove123, PlayerX_ColumnMove1); // Player O Move 1 // X // O // agameoftictactoe.placemarkerat(playero_rowmove12, PlayerO_ColumnMove1); // Player X Move 2 // X X
26 120 CHAPTER 4 테스트주도개발 // O // agameoftictactoe.placemarkerat(playerx_rowmove123, PlayerX_ColumnMove2); // Player O Move 2 // X X // O O // agameoftictactoe.placemarkerat(playero_rowmove12, PlayerO_ColumnMove2); // Player X Move 3 // X X X // O O // agameoftictactoe.placemarkerat(playerx_rowmove123, PlayerX_ColumnMove3); Assert.AreEqual(GameStatus.PlayerXWins, agameoftictactoe.status()); 이코드가컴파일이되도록하려면현재상태를표시할열거자클래스를추가해야할뿐아니라게임의현재상태를리턴하는메서드도추가해야한다. 틱택토게임은다음의다섯가지상태중하나만을가질수있다. 1. 플레이어 X 가승리했다. 2. 플레이어 O 가승리했다. 3. 게임이비겼다. 4. 플레이어 X 가표시할차례이다. 5. 플레이어 O 가표시할차례이다. 그러면 Model 프로젝트에 GameStatus라는이름의 C# 소스파일을추가하고다음과같이열거자를정의해보자. namespace ProEnt.Chap4.TicTacToe.Model public enum GameStatus PlayerXWins = 1, PlayerOWins = 2, GameDrawn = 3,
27 TDD 예제 : 틱택토게임 121 AwaitingPlayerXToPlaceMarker = 4, AwaitingPlayerOToPlaceMarker = 5 이제게임의현재상태를리턴하는메서드를다음과같이추가하면테스트가컴파일될것이다. namespace ProEnt.Chap4.TicTacToe.Model public class TicTacToeGame... public GameStatus Status() return GameStatus.GameDrawn; 자, 이제여러분은컴파일은되지만실패하는테스트코드를구현했다. 다시말하지만, TDD의규칙을정확하게따르고자한다면여러분은테스트에통과할수있는최소한의코드만을작성해야하며, 다시말해 Status 메서드를다음과같이수정해야한다. namespace ProEnt.Chap4.TicTacToe.Model public class TicTacToeGame... public GameStatus Status() return GameStatus.PlayerXWin; 그러나여러분은 TDD의철학을따르기위해서는규칙을지키는것이좋지만그것이법은아니기에반드시그렇게해야하는것은아니라는점을알고있을것이다. 따라서시간을보다효율적으로활용하려면게임에서누군가승리했는지를판단하기위해각각의행을검사하는코드를작성하는것이좋다.
28 122 CHAPTER 4 테스트주도개발 namespace ProEnt.Chap4.TicTacToe.Model public class TicTacToeGame... public GameStatus Status() GameStatus GameStatus = Model.GameStatus.GameDrawn; for (int Row = 0; Row <= 2; Row++) if ((this.board[row, (int)column.one] == (int)player.x && this.board[row, (int)column.two] == (int)player.x && this.board[row, (int)column.three] == (int)player.x)) GameStatus = GameStatus.PlayerXWins; if ((this.board[row, (int)column.one] == (int)player.o && this.board[row, (int)column.two] == (int)player.o && this.board[row, (int)column.three] == (int)player.o)) GameStatus = GameStatus.PlayerOWins; return GameStatus; 이렇게변경한코드는테스트에는통과하지만그다지보기에는좋지않으며, 향후에여러분이검사해야할다른상태를리턴해야할필요가있으므로리팩토링이필요하다. 메서드추출리팩토링신공으로 Status 메서드를다음과같이정리해보자. namespace ProEnt.Chap4.TicTacToe.Model public class TicTacToeGame... public GameStatus Status()
29 TDD 예제 : 틱택토게임 123 GameStatus GameStatus = Model.GameStatus.GameDrawn; if (isawinner(player.o)) GameStatus = Model.GameStatus.PlayerOWins; else if (isawinner(player.x)) GameStatus = Model.GameStatus.PlayerXWins; return GameStatus; private bool isawinner(player Player) bool winner = false; for (int Row = 0; Row <= 2; Row++) if ((this.board[row, (int)column.one] == (int)player && this.board[row, (int)column.two] == (int)player && this.board[row, (int)column.three] == (int)player)) winner = true; return winner; 이제모든테스트를실행해보면모두테스트를통과할것이다. 마지막테스트코드를작성할때불현듯떠오른생각은게임의상태는누군가승리하거나혹은게임이비기지않은이상플레이어 X나플레이어 O가표시해야할순서인상태가있을수있다는것이다. 현재게임의상태는승자가없다면게임이비긴것으로표시되고있다. 이동작을확인하기위해서는코드를구현하기에앞서테스트코드를구현해야한다. 다음과같이새로운테스트메서드를추가해보자.
30 124 CHAPTER 4 테스트주도개발 [Test] public void The_Game_Status_Should_Be_Awaiting_Either_Player_X_Or_O_If_The_Game_Is_Not_Won_ Or_Drawn() Row PlayerXrowToPlace = Row.One; Column PlayerXcolumnToPlace = Column.One; TicTacToeGame agameoftictactoe = new TicTacToeGame(); Assert.AreEqual(GameStatus.AwaitingPlayerXToPlaceMarker, agameoftictactoe.status()); agameoftictactoe.placemarkerat(playerxrowtoplace, PlayerXcolumnToPlace); Assert.AreEqual(GameStatus.AwaitingPlayerOToPlaceMarker, agameoftictactoe.status()); 이테스트가성공하려면두플레이어중누군가게임에승리했는지를검사해야하며, 그렇지않다면누가표시할차례인지를알아내야한다. 따라서 Status 메서드는다음과같이변경되어야한다. namespace ProEnt.Chap4.TicTacToe.Model public class TicTacToeGame... public GameStatus Status() GameStatus GameStatus = Model.GameStatus.GameDrawn; if (IsAWinner(player.o)) GameStatus = Model.GameStatus.PlayerOWins; else if (IsAWinner(player.x)) GameStatus = Model.GameStatus.PlayerXWins; else if (WhoseTurn() == player.x) GameStatus = Model.GameStatus.AwaitingPlayerXToPlaceMarker; else GameStatus = Model.GameStatus.AwaitingPlayerOToPlaceMarker; return GameStatus;
31 TDD 예제 : 틱택토게임 Model 프로젝트와 Test 프로젝트를다시빌드하고테스트를실행해보면승자가없거나게임이비기지않은상태에서도게임의상태가올바르게리턴되는것을확인할수있다. 다음테스트는 플레이어 X가한열에세개의 X 표시를모두하면플레이어 X가승리한다 라는항목이다. 이테스트를위한코드는앞서작성한코드와유사하지만이번에는각행별로검사를수행해야한다. 테스트코드는다음과같다. [Test] public void If_Player_X_Gets_Three_Xs_In_A_Column_Then_The_Game_Is_Won_By_Player_X() Row PlayerX_RowMove1 = Row.One; Row PlayerX_RowMove2 = Row.Two; Row PlayerX_RowMove3 = Row.Three; Column PlayerX_ColumnMove123 = Column.One; Row PlayerO_RowMove12 = Row.One; Column PlayerO_ColumnMove1 = Column.Two; Column PlayerO_ColumnMove2 = Column.Three; TicTacToeGame agameoftictactoe = new TicTacToeGame(); // Player X Move 1 // X // // agameoftictactoe.placemarkerat(playerx_rowmove1, PlayerX_ColumnMove123); // Player O Move 1 // X O // // agameoftictactoe.placemarkerat(playero_rowmove12, PlayerO_ColumnMove1); // Player X Move 2 // X O // X
32 126 CHAPTER 4 테스트주도개발 // agameoftictactoe.placemarkerat(playerx_rowmove2, PlayerX_ColumnMove123); // Player O Move 2 // X O O // X // agameoftictactoe.placemarkerat(playero_rowmove12, PlayerO_ColumnMove2); // Player X Move 3 // X O O // X // X agameoftictactoe.placemarkerat(playerx_rowmove3, PlayerX_ColumnMove123); Assert.AreEqual(GameStatus.PlayerXWins, agameoftictactoe.status()); 이테스트를실행해보면테스트에실패하게된다. 이는플레이어가승리했는지를검사하기위해수평으로각행을점검했기때문이다. 올바른테스트를위해서는세개의 X가각행에존재하는지확인하는코드를작성해야한다. TicTacToeGame 클래스의 IsAWinner 메서드를다음과같이수정하여 X 혹은 O 플레이어가승리했는지를각행별로검사하도록구현해보자. namespace ProEnt.Chap4.TicTacToe.Model public class TicTacToeGame... private bool IsAWinner(player Player) bool winner = false; for (int Row = 0; Row <= 2; Row++) if ((this.board[row, (int)column.one] == (int)player && this.board[row, (int)column.two] == (int)player && this.board[row, (int)column.three] == (int)player)) winner = true;
33 TDD 예제 : 틱택토게임 127 for (int Column = 0; Column <= 2; Column++) if ((this.board[(int)row.one, Column] == (int)player && this.board[(int)row.two, Column] == (int)player && this.board[(int)row.three, Column] == (int)player)) winner = true; return winner; 이제 Model 프로젝트와 Tests 프로젝트를다시빌드하고전체테스트를실행해보면모든테스트가통과하게될것이다. 이번테스트에서는 IsAWinner 메서드의분량이꽤커졌다. 따라서이메서드를리팩토링하는것이좋다. 다음테스트는플레이어 X가대각선으로승리의조건을만들었는지확인해야하므로일단테스트코드를작성하는것을중단하고 IsAWinner 메서드가모든조건에대응할수있도록수정하는것이좋겠다. [Test] public void If_Player_X_Gets_Three_Xs_In_A_Diagonal_Line_The_Game_Is_Won_By_Player_X() Row PlayerX_RowMove1 = Row.One; Row PlayerX_RowMove2 = Row.Two; Row PlayerX_RowMove3 = Row.Three; Column PlayerX_ColumnMove1 = Column.One; Column PlayerX_ColumnMove2 = Column.Two; Column PlayerX_ColumnMove3 = Column.Three; Row PlayerO_RowMove12 = Row.One; Column PlayerO_ColumnMove1 = Column.Two; Column PlayerO_ColumnMove2 = Column.Three; TicTacToeGame agameoftictactoe = new TicTacToeGame(); // Player X Move 1 // X // // agameoftictactoe.placemarkerat(playerx_rowmove1, PlayerX_ColumnMove1);
34 128 CHAPTER 4 테스트주도개발 // Player O Move 1 // X O // // agameoftictactoe.placemarkerat(playero_rowmove12, PlayerO_ColumnMove1); // Player X Move 2 // X O // X // agameoftictactoe.placemarkerat(playerx_rowmove2, PlayerX_ColumnMove2); // Player O Move 2 // X O O // X // agameoftictactoe.placemarkerat(playero_rowmove12, PlayerO_ColumnMove2); // Player X Move 3 // X O O // X // X agameoftictactoe.placemarkerat(playerx_rowmove3, PlayerX_ColumnMove3); Assert.AreEqual(GameStatus.PlayerXWins, agameoftictactoe.status()); 이테스트코드역시여전히실패할것이다. 이번에는대각선으로도승리한플레이어가있는지를검사하는코드를추가해야한다. 이코드는 IsAWinner 메서드에추가할것이다. 지면을절약하기위해테스트코드에서는우측상단으로부터좌측하단방향으로의대각선을검사하는코드는생략할것이며, 혹시다운로드한예제코드에도포함되어있지않다면여러분은해당코드를구현해야한다. 플레이어 O가승리했는지검사하는로직도이와동일하다. namespace ProEnt.Chap4.TicTacToe.Model public class TicTacToeGame... private bool IsAWinner(player Player) bool winner = false;
35 TDD 예제 : 틱택토게임 129 for (int Row = 0; Row <= 2; Row++) if ((this.board[row, (int)column.one] == (int)player && this.board[row, (int)column.two] == (int)player && this.board[row, (int)column.three] == (int)player)) winner = true; for (int Column = 0; Column <= 2; Column++) if ((this.board[(int)row.one, Column] == (int)player && this.board[(int)row.two, Column] == (int)player && this.board[(int)row.three, Column] == (int)player)) winner = true; if (( this.board[(int)row.one, (int)model.column.one] == (int)player && this.board[(int)row.two, (int)model.column.two] == (int)player && this.board[(int)row.three, (int)model.column.three] == (int)player)) winner = true; if (( this.board[(int)row.one, (int)model.column.three] == (int)player && this.board[(int)row.two, (int)model.column.two] == (int)player && this.board[(int)row.three, (int)model.column.one] == (int)player)) winner = true; return winner; 이제승리를위한모든조건을만족하는코드를갖추게되었으므로 IsAWinner 메서드를리팩
36 130 CHAPTER 4 테스트주도개발 토링해보자. 메서드추출기법을이용하여승리한플레이어를검사하는로직을세개의메서드로분리할수있다. 이렇게함으로써코드의가독성을향상시켜더욱이해하기쉬운코드를작성할수있다. namespace ProEnt.Chap4.TicTacToe.Model public class TicTacToeGame... private bool IsAWinner(player Player) bool winner = false; if (IsThreeInARowWinner(Player) IsThreeInAColumnWinner(Player) IsThreeInADiagonalWinner(Player) ) winner = true; return winner; private bool IsThreeInADiagonalWinner(player Player) bool winner = false; if (( this.board[(int)row.one, (int)model.column.one] == (int)player && this.board[(int)row.two, (int)model.column.two] == (int)player && this.board[(int)row.three, (int)model.column.three] == (int)player )) winner = true; if (( this.board[(int)row.one, (int)model.column.three] == (int)player && this.board[(int)row.two, (int)model.column.two] == (int)player && this.board[(int)row.three, (int)model.column.one] == (int)player )) winner = true;
37 TDD 예제 : 틱택토게임 131 return winner; private bool IsThreeInAColumnWinner(player Player) bool winner = false; for (int Column = 0; Column <= 2; Column++) if ((this.board[(int)row.one, Column] == (int)player && this.board[(int)row.two, Column] == (int)player && this.board[(int)row.three, Column] == (int)player)) winner = true; return winner; private bool IsThreeInARowWinner(player Player) bool winner = false; for (int Row = 0; Row <= 2; Row++) if ((this.board[row, (int)column.one] == (int)player && this.board[row, (int)column.two] == (int)player && this.board[row, (int)column.three] == (int)player)) winner = true; return winner; 마지막테스트이자게임에서구현해야할상태들중마지막상태는 모든공간이채워지고승자가없으면게임은무승부가된다 항목이다. [Test] public void When_All_Squares_Are_Full_And_There_Is_No_Winner_The_Game_Is_A_Draw() TicTacToeGame agameoftictactoe = new TicTacToeGame(); Row currentrow;
38 132 CHAPTER 4 테스트주도개발 for (int R = 0; R <= 2; R++) currentrow = (Row)Enum.ToObject(typeof(Row), R); agameoftictactoe.placemarkerat(currentrow, Column.One ); agameoftictactoe.placemarkerat(currentrow, Column.Three); agameoftictactoe.placemarkerat(currentrow, Column.Two ); // Game Board After All Moves // X X O // O O X // X X O Assert.AreEqual(GameStatus.GameDrawn, agameoftictactoe.status()); 모든공간이채워진상태에서승자가없다면게임은무승부가된다. 따라서승자를판단한이후에는모든공간이채워져있는지를검사하는코드를추가하면된다. namespace ProEnt.Chap4.TicTacToe.Model public class TicTacToeGame... public GameStatus Status() GameStatus GameStatus = Model.GameStatus. Draw; if (isawinner(player.o)) GameStatus = Model.GameStatus.PlayerOWins; else if (isawinner(player.x)) GameStatus = Model.GameStatus.PlayerXWins; else if (GameIsDrawn()) GameStatus = Model.GameStatus. Draw; else if (WhoseTurn() == player.x) GameStatus = Model.GameStatus.AwaitingPlayerXToPlaceMarker; else GameStatus = Model.GameStatus.AwaitingPlayerOToPlaceMarker; return GameStatus;
39 TDD 예제 : 틱택토게임 133 private bool GameIsADraw() bool allsquaresused = true; for (int Row = 0; Row <= 2; Row++) for (int Column = 0; Column <= 2; Column++) if (this.board[row, Column] == 0) allsquaresused = false; return allsquaresused;... 여러분이리스트에미처작성하지않은테스트중하나는누군가게임에승리한이후의처리이다. 이경우에는게임이더이상진행되지않도록하는것이옳다고할수있기때문에이런경우에대한테스트코드도작성해야한다. 이를위해 게임에서누군가승리한후에는더이상게임을진행할수없다 는이름의테스트메서드를추가해야한다. 이경우게임에서누군가승리한상태를만들어야하기때문에메서드추출리팩토링기법을이용해앞에서의테스트를위해작성했던코드를재사용해보자. using Microsoft.VisualStudio.TestTools.UnitTesting; using ProEnt.Chap4.TicTacToe.Model; namespace ProfessionalEnterprise.Chap4.MSTests [TestFicture] public class TicTacToeGameTests... [Test] public void If_Player_X_Gets_Three_Xs_In_A_Row_Then_The_Game_Is_Won_By_Player_X()
40 134 CHAPTER 4 테스트주도개발 TicTacToeGame agameoftictactoe = GetThreeXsInARowWinningGame(); Assert.AreEqual(GameStatus.PlayerXWins, agameoftictactoe.status()); private TicTacToeGame GetThreeXsInARowWinningGame() Row PlayerX_RowMove1 = Row.One; Row PlayerX_RowMove2 = Row.Two; Row PlayerX_RowMove3 = Row.Three; Column PlayerX_ColumnMove123 = Column.One; Row PlayerO_RowMove12 = Row.One; Column PlayerO_ColumnMove1 = Column.Two; Column PlayerO_ColumnMove2 = Column.Three; TicTacToeGame agameoftictactoe = new TicTacToeGame(); // Player X Move 1 // X // // agameoftictactoe.placemarkerat(playerx_rowmove1, PlayerX_ColumnMove123); // Player O Move 1 // X O // // agameoftictactoe.placemarkerat(playero_rowmove12, PlayerO_ColumnMove1); // Player X Move 2 // X O // X // agameoftictactoe.placemarkerat(playerx_rowmove2, PlayerX_ColumnMove123); // Player O Move 2 // X O O // X // agameoftictactoe.placemarkerat(playero_rowmove12, PlayerO_ColumnMove2);
41 TDD 예제 : 틱택토게임 135 // Player X Move 3 // X O O // X // X agameoftictactoe.placemarkerat(playerx_rowmove3, PlayerX_ColumnMove123); return agameoftictactoe;... [Test] public void A_Player_Can_Make_No_More_Moves_After_A_Game_Is_Won() TicTacToeGame agameoftictactoe = GetThreeXsInARowWinningGame(); Assert.AreEqual(GameStatus.PlayerXWins, agameoftictactoe.status()); // 게임이종료되면빈공간이라도표시를할수없다. Assert.IsFalse(aGameOfTicTacToe.CanPlaceMarkerAt(Row.Three, Column.Three )); 현재코드에는게임이종료됐는지확인하는메서드가존재하지않기때문에이테스트는당연히실패하게된다. 테스트를통과하려면단순히게임에서누군가이겼거나혹은무승부인지게임의상태를검사하는코드를추가하면된다. 가장쉬운방법은현재게임에서플레이어중한명이표시를할차례인지를검사하는것이다. namespace ProEnt.Chap4.TicTacToe.Model public class TicTacToeGame... public bool CanPlaceMarkerAt(Row row, Column column) if (Status() == GameStatus.AwaitingPlayerOToPlaceMarker Status() == GameStatus.AwaitingPlayerXToPlaceMarker )
42 136 CHAPTER 4 테스트주도개발 return this.board[(int)row, (int)column] == 0; return false;... 이제여러분이작성했던모든테스트를통과했으므로이제이소프트웨어는기본적인요구사항을모두만족한다는것을보장할수있을뿐아니라코드를변경하거나리팩토링하더라도그에따른영향은없는지를즉시판단할수있게되었다. 또한이테스트코드는틱택토게임의규칙을이해하기위한용도로도활용할수있으므로향후에다른개발자도여러분의게임애플리케이션에구현된로직을쉽게이해할수있게된다. 틱택토게임의전체소스는다음과같다. namespace ProEnt.Chap4.TicTacToe.Model public class TicTacToeGame private int[,] Board = new int[3, 3]; private player currentplayer; public TicTacToeGame() currentplayer = player.x; public player WhoseTurn() return currentplayer; public bool CanPlaceMarkerAt(Row row, Column column) if (Status() == GameStatus.AwaitingPlayerOToPlaceMarker Status() == GameStatus.AwaitingPlayerXToPlaceMarker ) return this.board[(int)row, (int)column] == 0; return false;
43 TDD 예제 : 틱택토게임 137 public void PlaceMarkerAt(Row row, Column column) if (CanPlaceMarkerAt(row, column)) this.board[(int) row, (int) column] = (int) WhoseTurn(); ChangeCurrentPlayer(); else throw new ApplicationException( string.format("square Row:0, Column:1 already occupied by 2", row.tostring(), column.tostring(), (player)enum.toobject(typeof(player), this.board[(int)row, (int)column]))); private void ChangeCurrentPlayer() if (this.currentplayer == player.x) this.currentplayer = player.o; else this.currentplayer = player.x; public GameStatus Status() GameStatus GameStatus = Model.GameStatus.Draw; if (IsAWinner(player.o)) GameStatus = Model.GameStatus.PlayerOWins; else if (IsAWinner(player.x)) GameStatus = Model.GameStatus.PlayerXWins; else if (GameIsADraw()) GameStatus = Model.GameStatus.Draw; else if (WhoseTurn() == player.x) GameStatus = Model.GameStatus.AwaitingPlayerXToPlaceMarker; else
44 138 CHAPTER 4 테스트주도개발 GameStatus = Model.GameStatus.AwaitingPlayerOToPlaceMarker; return GameStatus; private bool GameIsADraw() bool allsquaresused = true; for (int Row = 0; Row <= 2; Row++) for (int Column = 0; Column <= 2; Column++) if (this.board[row, Column] == 0) allsquaresused = false; return allsquaresused; private bool IsAWinner(player Player) bool winner = false; if (IsThreeInARowWinner(Player) IsThreeInAColumnWinner(Player) IsThreeInADiagonalWinner(Player) ) winner = true; return winner; private bool IsThreeInADiagonalWinner(player Player) bool winner = false; if (( this.board[(int)row.one, (int)model.column.one] == (int)player && this.board[(int)row.two, (int)model.column.two] == (int)player && this.board[(int)row.three, (int)model.column.three] == (int)player ))
45 TDD 예제 : 틱택토게임 139 winner = true; if (( this.board[(int)row.one, (int)model.column.three] == (int)player && this.board[(int)row.two, (int)model.column.two] == (int)player && this.board[(int)row.three, (int)model.column.one] == (int)player )) winner = true; return winner; private bool IsThreeInAColumnWinner(player Player) bool winner = false; for (int Column = 0; Column <= 2; Column++) if ((this.board[(int)row.one, Column] == (int)player && this.board[(int)row.two, Column] == (int)player && this.board[(int)row.three, Column] == (int)player)) winner = true; return winner; private bool IsThreeInARowWinner(player Player) bool winner = false; for (int Row = 0; Row <= 2; Row++) if ((this.board[row, (int)column.one] == (int)player && this.board[row, (int)column.two] == (int)player && this.board[row, (int)column.three] == (int)player)) winner = true; return winner;
46 140 CHAPTER 4 테스트주도개발 지금까지의내용을통해테스트주도개발이어떤것인지에대해학습해보았다. 전체적으로코드의디자인이뛰어나다고는할수없지만최소한의코드로전체게임을구현할수있었으며, 테스트를통과하기위한코드만을구현하였다. 더좋았던점은모든테스트가완료되고더이상테스트할기능이없게되는시점에여러분이해야할작업이완료되었음을알수있게되었다는점이다. 프로그램을구현하기위한코드를먼저작성했다면코드가어떻게구현되었을지생각해보자. 아마도정확한규칙을이해하지못한채보드객체나플레이어객체를먼저구현했을것이다. 그러다보면프로그램의요구사항과맞닥뜨리게되고, 마지막에는코드가전체적으로동작하는지를확인하기위해단위테스트를추가하든가혹은그렇게하지도못하고일을마무리할수도있었을것이다. 테스트코드를먼저작성하면서애플리케이션의디자인을구성했기때문에우선최소한의노력으로요구사항을만족하는코드를만들어낼수있다. 가장좋은점은한두가지메서드가자신의역할이아닌다른역할을해야하거나게임의승자를검사하는로직이다른클래스에작성되어야한다면애플리케이션의디자인을손쉽게리팩토링할수있으며, 이런리팩토링과정이 TicTacToeGame 클래스의다른동작에어떤영향을미치지는않는지를테스트코드들을통해곧바로확인할수있다는점이다. 테스트프레임워크 지금까지의예제에서는테스트프레임워크로 NUnit 프레임워크를사용했지만 NUnit 프레임워크가유일한테스트프레임워크는아니며, NUnit 애플리케이션을실행하는것이테스트코드를실행하는유일한방법도아니다. NUnit 틱택토게임을구현하는동안우리는 NUnit 프레임워크를사용했다. NUnit은자바환경에서사용하던 JUnit을.NET으로포팅한오픈소스제품이며,.NET 환경에서도널리사용되고있다. NUnit에대한보다자세한내용은 MS Test NUnit과동일한기능을제공하는마이크로소프트의통합테스트도구로문법에는다소차이가있지만 Visual Studio에통합되어제공된다.
47 TDD 예제 : 틱택토게임 141 MS Test 프레임워크는 Visual Studio 2008 Professional 혹은그이상의버전에서제공된다. MbUnit MbUnit은또다른오픈소스테스트프레임워크이다. 이제품은다양한기능을제공하며손쉽게확장이가능하다. 만일 NUnit이나 MSTest 프레임워크에한계를느낀다면 MbUnit을필요에따라확장하여사용할수도있다. MbUnit에대한보다자세한내용은 TestDriven.NET TestDriven.NET 자체는테스트프레임워크가아니지만 Visual Studio에서테스트프레임워크를선택할수있도록해주는애드인 add-in 이다. 이도구를이용하면 NUnit, MbUnit 및 MSTest 프레임워크는물론다른모든오픈소스테스트프레임워크를통합할수있어테스트주도개발에대한경험을향상시킬수있다. 개인용버전은무료이며, 보다자세한내용은 테스트가가능한요소들을정의하기 이제여러분은 TDD 개발방법론과절차에대해이해하게되었을것이므로이제는어떤부분에대해테스트를진행해야하는지를고민해보자. 100% 의코드커버리지 code coverage 를갖춘다는것은완벽한단위테스트집합을갖춘다는뜻은아니다. 이런생각은품질보다는단위테스트의개수에집착하는것일뿐이다. 개발방법론의규칙과이를비즈니스의요구사항에실용적으로반영하는것사이에는항상타협이필요하다. 이번섹션에서는단위테스트에대해여러분이해야할것과하지말아야할것에대해자세히알아보도록하자. 소소한코드까지테스트하지말라 TDD의소개단계에서이미읽어보았겠지만 TDD는여러분이작성하는코드모듈의동작을검증하는단위테스트를작성함으로써여러분의코드를위한디자인을정립해나가기위한것이다. 따라서여러분이작성할테스트코드는기본적으로고수준의추상화를필요로한다. 따라서테스트를수행할때는세부적인구현보다는고수준의요구사항에대해생각하는것이좋다. 이런고수준테스트를진행하다보면세부적인객체들이필요해질때도있지만, 세부적인객체들에대한단위테스트가항상장점만을가지는것은아니다. 전자상거래서비스에서사용가능한모든통화단위를리턴하는서비스를검증하기위한테스트를예로들어보자. 아무런동작도수행하지
48 142 CHAPTER 4 테스트주도개발 않으며, 단지데이터전송객체 DTO: Data Transfer Object 로사용되는현재의통화단위객체에값을대입하거나가져오는속성에대한테스트코드를작성하고싶지는않을것이다. 단지속성만을가지며동작은수행하지않는간단한객체에대해단위테스트를수행하는것은아무런의미가없다. 이런객체들을테스트하는것은단위테스트코드에아무런가치를부여하지않으며, 최악의경우테스트코드들을어지럽힐뿐아니라더가치있는단위테스트들을발견하지못하게한다. TDD 프로세스를글자그대로해석하는것과실제시스템이필요로하는개별적이며단위테스트가필요한부분들을찾아내는것사이에는타협이필요하다. 사실단위테스트는뭔가잘못되어가고있거나혹은나중에변경될우려가있는부분을대상으로해야한다. 모든단일시나리오에대해테스트코드를작성한다면아무런가치도없는수십만개의테스트코드를작성하게될것이다. 서드파티모듈에대해테스트하지말라여러분이작성하지말아야할또다른단위테스트들은.NET 프레임워크자체나서드파티 API 들을테스트하기위한것들이다. 여러분이참조하는서드파티도구들을믿지못하거나혹은믿지못할것처럼보인다면이런도구들은사용하지말아야한다. 다시말하지만여러분이스스로판단해야한다. 참조되는어셈블리가시스템이핵심기능을제공하며비즈니스에민감한부분이라면그도구가필요로하는기능을제공하는지를명확히해야한다. 다시말해도구를의심하게되는순간단위테스트코드를작성하게된다. 적정한추상화수준에서테스트를수행하라단위테스트의목적은애플리케이션의실행을방해할수있는로직의전체적인위험을줄이기위한것이므로여러분이작성하는테스트코드가소프트웨어를구성하는고수준의추상화된모듈들을대상으로하는것이중요하다. 저수준의상세한코드들을맹목적으로테스트하는것은매우지루하고하기싫은작업이될뿐이며, 결국모든테스트코드를함께검증하는과정을거스르게할수도있다. 비즈니스가중점을두고있는부분들을검증하기위해서단위테스트를작성하는것만이최선의방법은아니다. 개발자들은코드로직에대한최상의검증이단위테스트를통해이루어질것인지아니면실제동작하는것을눈으로확인해야할것인지를항상최선의판단과경험을토대로결정해야한다.
49 TDD 예제 : 틱택토게임 143 경계조건에대한테스트순수주의자들은코드를완벽하게테스트하려면모든경계조건을테스트해야한다고말한다. 경계조건을테스트한다는것은테스트코드에서여러가지극단적인값들을사용하는것을의미한다. 만일오늘이후의날짜를전달받는메서드에과거의날짜나오늘날짜가전달되면이를어떻게처리할것인가? 다시말하자면, 경계조건을테스트할수는있지만반드시그렇게해야할까? 소프트웨어개발과관련된이슈들에대한여러가지답변들과마찬가지로이는필요에따라다르게대처할수있다. 즉, 뭔가잘못된경우어떤일이발생할것인지에따라다르다는것이다. 만일테스트중인부분이비즈니스에민감한부분이라면다양한경계조건에대해테스트를해야한다. 그렇지않다면기껏해야 InvalidArgumentException 예외가발생할뿐이며, 그런다고세상이끝나는것도아니므로개발자가스스로판단해야한다. 무엇을테스트하고무엇을테스트하지말아야할지판단하는것은여러분의상식을활용하는것이다. 상식은경험을통해더나아질수있다. 각각의코드에단위테스트가필요한지그리고 100% 의코드커버리지가실제로듣기만큼좋은것인지를가늠해야한다. TDD 방법론을글자그대로받아들이는것과실제적용에있어서는항상타협이필요한만큼 TDD에대한경험을쌓아갈수록작업을빨리마무리하기위한지름길을알게될것이다. 앞서언급했듯이시간이흐름에따라여러분과팀의다른구성원들이해야할일을어렵지않게결정할수있게되면이러한타협을해야할때가올것이다. 궁극적으로별다른방법이없고여러분이아직의심에서벗어나지못했다면우선테스트코드를작성하라. 나중에얼마든지제거할수있다. 이제여러분이어떤것을테스트하느냐에따라여러분이작성한테스트코드가효과적이며도움이될것인지그렇지않을것인지를충분히알수있게되었으리라믿는다. 유용한단위테스트작성하기 좋은단위테스트의조건은무엇일까? 여러분이작성한단위테스트가효과적이며, 실제로동작함은물론리팩토링시에진정한가치를제공해줄수있는지를판단하기위한항목은다음과같다. 테스트는빠르게실행되어야한다. 테스트는반드시자동화되어실행할수있어야한다. 테스트는원자성을가져야한다. 테스트는반복수행할수있어야한다.
50 144 CHAPTER 4 테스트주도개발 테스트는명시적이며가독성이뛰어나야한다. 테스트는독립적이어야한다. 테스트는손쉽게설정할수있어야한다. 테스트는모든면을고려해야한다. 테스트는빠르게실행되어야한다쉽게말해테스트코드가느리게동작한다면여러분은물론다른누구라도테스트를빈번하게수행하지않을것이며, 따라서테스트의활용도가떨어지게된다. 테스트의실행속도가느리면귀한시간을테스트를실행하느라허비하게되므로테스트는반드시빠르게실행되어야한다. 이로인해여러분의작업주기를빠르게가져갈수있으며, 기능을추가하거나코드를리팩토링했을때버그를만들어내지않았음을확인할수있게된다. 테스트코드가자연스럽고빠르게실행되도록하는유일한방법은가상객체를이용하여시스템외부로부터의의존성을제거하는것이다. 만일단위테스트코드가데이터베이스에연결을시도하거나웹서비스를호출한다면테스트가메모리에서실행될때보다훨씬느리게동작할것이다. 의존성을가진인터페이스에대해가상객체를사용하면테스트코드를독립적으로실행할수있으며, 항상일관된결과를가져온다는것을보장할수있다. 가상객체에대해서는이장의후반부에서더자세히살펴보기로하자. 데이터베이스연결을수행하는통합테스트를작성할때에도이런코드를별도의어셈블리에분리하여구현함으로써테스트코드가빠르게동작하도록구현할수있다. 많은소프트웨어제조사들은소스코드를소스제어저장소에체크인하기전에전체단위테스트를실행하는데, 이런경우테스트코드가느리게동작하면개발자들이하루일과를마무리하면서자신들이작성한코드를검증하는것을꺼리게되므로테스트코드가빨리동작하는것이매우중요하다. 테스트는반드시자동화되어실행할수있어야한다코드의변경사항이미치는영향에대해빠르게판단할수있으려면여러분이나팀의구성원들이버튼하나만클릭해도테스트코드가동작할수있어야한다. 만일테스트코드를실행하는것자체가쉽지않거나별도의설정이필요하다면개발자들은테스트코드를실행하는것을좋아하지않을것이다. 간단히말해개발자들은소스제어저장소로부터최신버전의소스코드를내려받으면아무런추가설정없이도테스트코드를실행할수있어야한다. 테스트코드의실행이자동화되어손쉽게실행할수있다면개발자들이코드를업데이트할때도움이된다. 테스트가설정문제로실패하게되면개발자들은테스트코드에대해신뢰하지않
51 TDD 예제 : 틱택토게임 145 게되어테스트코드로서의가치가떨어지게된다. 따라서언제라도테스트를실행할수있는지에대해항상확인해야한다. 테스트는원자성을가져야한다여러분은테스트코드를몇번을실행하든항상같은결과를얻을수있어야한다. 따라서여러분이제어할수없는시간이나날짜, 데이터베이스의상태등을이용하는변수에의존해서는안된다. 대신항상일관된매개변수를이용하여테스트코드를언제몇번이라도실행할수있어야한다. 또한테스트코드를실행하기전에상태를가지고있던모든의존자원들은테스트가완료된이후원래상태로되돌아오는지를확인해야한다. 이경우셋업및해제이벤트를통해테스트가실행되기전의설정과실행이후의정리작업을수행할수있다. 이렇게하면항상깨끗한상태에서테스트가실행될수있다. 테스트는명시적이며가독성이뛰어나야한다테스트코드의집합은여러분의시스템이무엇을할수있고무엇을할수없는지를알려주는살아있는문서와도같은역할을하기때문에, 테스트코드에의미있고서술적인이름을부여하여다른개발자들이해당테스트가어떤동작을검증하기위한것인지를즉시이해할수있도록하는것이좋다. 테스트코드의이름은작성자의의도를알수있도록작성해야할뿐아니라명확하며이해가쉬워야한다. 여러분이작성하는테스트코드는프로그램의인터페이스를어떻게사용할것인지를보여주기때문에테스트코드의가독성은매우중요하다. 테스트코드에서중복된테스트를제거하고오래된테스트코드를삭제하여마치릴리즈할코드처럼전문적으로작성함으로써깔끔하고읽기쉬운상태를유지한다면, 이테스트코드는여러분에게더큰유용함과가치를가져다줄것이다. 테스트는독립적이어야한다테스트코드는반드시다른테스트코드로부터독립적이어야하며다른테스트코드에의존적이어서는안된다. 테스트가순서없이뒤죽박죽으로실행되는상황을가정한다면나중에실행될테스트는앞서실행된테스트에서설정한객체의상태에의존적이어서는안된다. 어떤하나의테스트코드의성공여부가다른테스트코드에영향을주어서는안된다. 객체의상태를변경하거나외부리소스를생성, 제거혹은기록하는테스트는상태해제메서드를이용하여테스트가완료된이후객체의원래상태를복원해야한다.
52 146 CHAPTER 4 테스트주도개발 테스트는손쉽게설정할수있어야한다테스트코드를설정하느라오랜시간을보낸덕분에실제릴리즈할코드를작성할시간이부족하다면뭔가잘못된것이다. 테스트코드는직관적이어야하며손쉽게설정이가능해야한다. 만일설정을위한코드를작성하느라시간을허비했다면여러분이테스트하려는코드를의미있는섹션에서분리하거나동일한객체의동일한상태를필요로하는다른테스트코드와공유할수있는설정루틴을만드는것이좋다. 테스트커버리지와다각도테스트하나의테스트에통과했다고해서로직자체가올바르게동작한다고보장할수는없다. 앞서작성한틱택토게임에서보았듯이여러분은테스트를통과하기위한최소한의코드만을작성했다. 그러나간혹이코드는다른테스트시나리오에서는올바르게동작하지않을수도있음을알게되었다. 여러분은 99% 의경우테스트를통과할수있는일반적인인수는물론극단적인경계값을이용하여테스트를수행할필요가있다. 요약하자면테스트코드도실제릴리즈할코드처럼전문적인코드로취급하면테스트코드는그만큼의보답을할것이다. 테스트코드는여러분이프로젝트에너무깊숙이빠져들때경고를해주는안전망을제공할것이다. 더이상테스트코드가필요없게되면이를제거하여전체적으로테스트코드가의미없는코드들덕분에어지러워지는것을방지해야한다. 테스트코드의이름은작성자의의도를충분히표현할수있도록가능한서술적으로작성해야한다. 기억할것은테스트코드가실제로릴리즈될코드가아니라는것이며, 여러분의프로그램이할수있는것과그렇지않은것을표현하기위한것이므로테스트코드의이름이명확할수록여러분과다른개발자들에게더가치있는것이된다. 마지막으로테스트코드를손쉽게설정하여실행할수있도록해야한다. 설정이어렵거나느리게실행되는테스트는여러분과다른개발자들이테스트코드를실행하는것을기피하게만들뿐이다. 그렇게되면버그가양산될것이며형편없는품질의코드가만들어질것이다. 다시말하지만일상생활과마찬가지로여러분스스로가판단해야한다. 테스트코드를설정하는데많은시간이필요하다면여러분은실제릴리즈코드를구현하기위해더많은시간이필요하게되므로차라리프로그램의기능을수동으로테스트하거나보다작은단위로나누는것이더효율적이다. 지금까지여러분은 TDD가무엇이며, 이개념을어떻게적용해야하는지, 어떤것을테스트해야하는지, 그리고테스트코드들을어떻게하면더효율적으로구성할수있는지에대해학습했다. 이제는 TDD를따랐을때얻을수있는현실적인이점이무엇이며, 여러분의투자가어떤결실을맺을수있는지에대해알아보자.
53 TDD 예제 : 틱택토게임 147 자동화 - 실질적인이점 TDD를통해얻을수있는가장첫번째이점중하나는프로그램의구현을완료하면여러분의기반코드를구성하는각각의로직을위한테스트코드들을얻을수있다는것이다. 이수많은테스트들은마치보험약관같은것이어서나중에어떤형태로코드가변경되더라도그영향을곧바로알수있으며, 만일변경사항이기존의모듈에버그를유발시키게된다면그즉시알수있게된다. TDD 방법론을따름으로써이룰수있는것은소프트웨어내의위험을줄을수있다는것이다. 버튼만클릭하면여러분의소프트웨어가요구대로동작하는지를언제든확인할수있으며, 더욱중요한것은다른개발자가대량의코드를변경한이후에자신만의방법으로디버그를수행할필요없이이테스트코드들을실행해보면된다는것이다. 단위테스트를자동화함으로써얻을수있는현실적인이점은수동테스트에대한필요성을감소시킬수있다는것이다. 주요테스트코드들을자동화함으로써인력의간섭을줄일수있다. 개발자에게모든코드시나리오에대해수동으로모든테스트와디버깅을진행하라는무자비한일을시키는것보다는테스트프레임워크가 1,000개의테스트를실행하도록하는것이훨씬쉽다. 두사람의개발자가똑같을수는없다. 누군가는다른사람보다테스트를더잘할수있으므로코드에변경이일어났다고해서개발자들이모든로직을테스트하는것보다는테스트프레임워크에게맡긴다면버그의출현을더확실하게검출할수있다. 또한소프트웨어의다음기능을구현하기위한시간도확보할수있다는이점이있다. 정의에따르면, TDD 방법론을따를경우여러분은테스트가가능한코드를만들어낼수있다. 테스트가능한코드는디자인적으로느슨하게결합되어있으며모듈화된코드를말한다. 각각의기능들을단일책임을가진클래스로분리하면유지보수와확장성에대한요구사항을줄일수있어비즈니스요구사항의변경에대응하기위한코드의유연성을향상시킬수있다. 이번장의후반부에서는실제코드가가지는의존성을가상객체로대체함으로써코드모듈을느슨하게결합된형태로유지할수있는방법에대해학습하게될것이다. 지금까지의내용들은코드를리팩토링하거나디자인을결정할때개발자인여러분들에게확신을안겨줄수있을것이다. 테스트코드를통해서여러분의코드가올바르게동작하는지여부를곧바로알수가있다. 이번장의후반부에서는디자인패턴을이용하여코드를보다단순하게디자인할수있는방법에대해학습한다. 개요부에서읽었듯이 TDD는여러분이작성한코드가올바르게동작한다는것을증명할뿐아니라소프트웨어의디자인에도중요한영향을미친다. TDD는실제릴리즈할코드를작성하기에앞서여러분이기대하는결과를먼저테스트함으로써여러분이해결하고자하는문제에대해
54 148 CHAPTER 4 테스트주도개발 완벽하게이해하도록만든다. 즉, 여러분이소프트웨어의요구사항을분명하게이해하는것뿐아니라최종 API를구현할수있도록해준다. 테스트코드를먼저디자인함으로써여러분은인터페이스가어떻게동작할것인지를구상할필요가있다. 또한여러분이구현한모듈을실제로사용할사람의관점에서테스트코드를작성하게되며, 코드자체의기능보다는코드의인터페이스에더초점을맞추게된다. 그러려면기능이동작하도록하기전에클라이언트 ( 테스트 ) 코드와 API 사이의상호작용에대해생각해야하며, 그로인해사용이쉬우면서도다른개발자가의도를쉽게파악할수있는, 간단하면서도유연한 API를작성하게된다. 여러분이작성한테스트코드는소프트웨어가할수있는일과할수없는일의목록이된다. 또한 API와어떻게상호작용할수있는지를보여주는일련의예제코드로서의역할도수행할수있다. 따라서여러분이작성한코드가계속해서발전하는데있어살아숨쉬는문서의역할을수행할수있다. 바로이런점때문에테스트코드의이름을지정하는것과테스트코드자체를깔끔하게유지하는것이중요하다. 틱택토예제를위해여러분이구현했던테스트코드를읽어보면게임자체와그규칙에대해알아야할모든것들을배울수있다. 무엇을테스트해야할지를알아보았던이전섹션에서지적했듯이여러분이작성하는초기의테스트코드는모듈의구체적인구현보다는추상화에초점을맞춘다. 이렇게하면개발자는모듈의실제비즈니스적가치에초점을맞추게되며, 그후코드들을검증하고에러처리나유효성검사와같은경계사항들을테스트하는데사용할수있게된다. 이런과정을통해실제로동작하는핵심기능들을구축할수있고, 이를토대로여러분의릴리즈코드를개발해나갈수있게된다. 이때작성되는코드들은테스트에통과하기위한목적으로작성되기때문에여러분은 YAGNI (You Aren't Gonna Need It) 디자인패턴을활용하는셈이다 ( 옮긴이 _YAGNI 패턴이란, 주로익스트림프로그래밍방법론에등장하는것으로실제로필요해지기전까지는어떤코드도추가하지말것을권장하는프로그래밍원칙이다 ). 프로그램이필요로하는코드만을작성하고테스트에실패하는경우에도같은방식으로테스트를통과하는코드를작성하게된다면여러분은모든경우의코드를검증할수있는테스트코드집합을갖추게된다. 최소한의코드만으로이와같은테스트코드를작성한다면경우에따라프로젝트의불필요한복잡성을줄일수있다. 반드시필요한코드만을작성하면여러분과팀의생산성을향상시킬수있다. 잘갖춰진단위테스트코드들은한사람의개발자에대한의존성을줄일수도있다. 이러한의존성은주로트럭팩터 truck factor 라고부른다. 트럭팩터란, 팀의몇몇구성원이실제프로젝트에서심각한문제가발생하기전까지는대부분의업무를처리하게되는상황을의미한다. 테스트코드를작성하면새로운개발자들이기존의코드를망치게될경우테스트코드가이를바로알
55 리팩토링 149 수있게해주기때문에새로운개발자들이손쉽게프로젝트에적응할수있게되며, 이미존재하는기반코드를빠르게학습할수있게된다. 또한실제로릴리즈될코드가어떻게작성되어야하는지를보여주기때문에새로운개발자에게더큰가치를제공하게된다. 이는 TDD의특징인유기적인문서와관련이있다. 요약하자면, TDD는여러분이소프트웨어를개발하는데있어곧바로활용할수있는다양하고실용적인이점을제공한다. 테스트를자동화하고실제코드를작성하기에앞서테스트코드를작성함으로써개발시에짊어질스트레스를날려버릴수있다. 또한여러분이작성한코드가동작한다는것과실제로작업을완료하기위한코드외에불필요한코드는존재하지않음을보장할수있다. 동일한기반코드로작업하는다른개발자들은자신들이변경하거나기능을추가할때테스트코드를통해기존코드의동작을검증할수있기때문에자신들의변경사항이기존코드의동작을방해하지않는다는것을보장할수있다. 짧은주기로작은단계의작업을수행하기때문에소프트웨어개발자체를통제할수있으며, 느슨하게결합된확장및유지보수가용이한고품질의코드를작성할수있게된다. 마지막으로, TDD의장점을모두취한다면여러분스스로가여러분의코드를신뢰할수있게된다는것이가장중요하다. 코드를수정하거나새로운기능을추가했을때즉각적인결과를알려줄수있는테스트코드들은여러분과팀에큰도움이될것이다. 또한여러분이작성한코드를신뢰할수있다면실제로코드를릴리즈할때나코드를수정하거나기능을추가해야할때더욱확신을갖게될것이다. 이번장의첫번째파트에서는여러분의코드가잘동작하는것은물론깔끔하게유지하는것이중요하다는것을알게되었다. 리팩토링이라고알려진코드정리작업은테스트코드를작성하는것만큼중요한주제이다. 리팩토링 제3장에서여러분은테스트주도개발의 레드- 그린- 리팩토링 단계에서세번째단계인리팩토링에대해간단히살펴본적이있다. 리팩토링이란, 기존의코드디자인을향상시키기위한방법이다. 틱택토게임예제에서는모든테스트가성공적으로수행되어코드가올바르게동작하게된후에는코드에대한리팩토링을수행하여코드자체의동작을변경하지않고도코드를더욱깔끔하고유지보수가용이하도록구성할수있는단계에이르렀었다. 간단히말하면, 사실그다
56 150 CHAPTER 4 테스트주도개발 지간단한일은아니지만코드는항상손쉽게변경이가능한구조를유지해야한다. 그렇다면왜코드를리팩토링해야하는걸까? 뭔가잘못되지않았다면고칠필요가없다 라고보는것이올바르지않을까? 리팩토링은코드의버그를수정하는것이아니며, 다른기능을추가하는것도아닌데대체왜해야하는걸까? 리팩토링의진정한가치는코드를보다이해하기쉽게하며, 여러분과다른개발자들이코드를유지보수하기쉽도록하는데있다. 마틴파울러 Martin Fowler 는리팩토링에대해다음과같이훌륭하게요약하고있다. 컴퓨터가이해할수있는코드는바보라도작성할수있다. 훌륭한프로그래머는인간이이해할수있는코드를작성한다. ( 마틴파울러, Refactoring, 1999년 Addison-Wesley Object Technology 시리즈에서 ) 코드를적절하게리팩토링하지않으면새로운기능을추가하거나기존기능을수정해야할때곧바로문제점으로나타날수있다. 코드를깔끔하게리팩토링하지않으면결국에는스파게티처럼뒤얽힌구조로인해작업이불가능하며유지보수가어려운상태가되고만다. 리팩토링을수행하는입장에서여러분은여러분이작성한코드를더욱잘이해할수있게되며, 따라서이를더간단하며더나은구조로리팩토링할수있다. 또한다른개발자들이여러분이작성한코드를더쉽게이해할수있도록잘알려진디자인패턴을이용하여리팩토링할수도있다. 리팩토링은 TDD의영역에만국한된것은아니지만, TDD와함께수행하면여러분이수행한리팩토링의영향을손쉽게파악할수있어여러분이변경한사항이모듈의동작에영향을미치지않는다는것을곧바로확인할수있다. 리팩토링을수행할때기억해야할가장중요한것은리팩토링은작은단계로진행되어야하며, 각리팩토링이완료된후에는반드시테스트코드를실행해야한다는것이다. TDD 방법론에따라짧은주기로작업을진행한다면버그의출현으로인한위험을감소시킬수있으며, 기존의테스트를통과하지못하는부분을손쉽게찾아낼수있다. 리팩토링은 TDD와밀접한관계가있다. 여러분이작성한테스트코드덕분에보다확신을가지고리팩토링을수행할수있으며, 코드리팩토링은코드를더욱간단명료하게하여더욱테스트하기쉽게만든다.
57 테스트주도개발환경에서의존성처리하기 151 리팩토링도구 테스트프레임워크와함께리팩토링에사용할수있는도구들에대해알아보자. ReSharper ReShaprer는 Visual Studio의애드인으로몇가지향상된기능을제공하는동시에강력한리팩토링기능을제공한다. 또한 NUnit 프레임워크와통합되어한번의클릭으로통합된단위테스트프레임워크를실행할수있다. 보다자세한내용은 Refactor Pro Refactor Pro는 ReSharper의모든기능을제공하지만사용자인터페이스를위한통합된테스트기능이제외되어있다. 어떤것을선택할지는개인의취향에따라다르겠지만둘다훌륭한제품임에는틀림이없다. 보다자세한내용은 을참고하기바란다. 테스트주도개발환경에서의존성처리하기 테스트코드를작성할때의핵심특성중하나는각기능에대한테스트가독립적으로이루어진다는것이다. 그러나제3장의 ReturnOrderService 클래스에서살펴보았듯이프로그래밍의강력함은복잡한문제를해결하기위해객체들이협력할때발휘된다. ReturnOrderService 클래스의 Process 메서드는고객에대한환불처리를 IPaymentGateway 인터페이스를구현한객체에게위임한다. 또한고객에게환불사실을알리기위한처리도 INotificationService 인터페이스를구현한객체에게위임한다. 다른모듈에의존적인로직을테스트할때간혹다른모듈들을포함해전체통합테스트를해야할때가있다. 특히존재하지않거나혹은의존객체가아직구현되지않은상황에서테스트를수행해야한다면상황은더욱악화될뿐이다.
58 152 CHAPTER 4 테스트주도개발 의존성을가진객체를위한테스트코드를작성해야한다면우선은실제객체의역할을대행할스텁 stub 객체 ( 혹은가상객체 ) 를구현할수있다. 이스텁객체의역할은테스트중인객체가필요로하는데이터를흉내내는것이다. 스텁객체는일반적으로단위테스트의실패와는무관하다. 스텁객체는단순히테스트중인객체가작업을완료하기위해필요로하는데이터를제공하는목적으로사용된다. 스텁객체를이용하면데이터베이스나웹서비스를호출하는서비스객체를실제구현과동일하게동작하는가상객체로대체함으로써의존성을손쉽게제거할수있어테스트를일관적이고빠르게수행할수있다. 스텁객체나가상객체를사용하는방법을연습하기위해휴가요청예약시스템을구현해보자. 그림 4-9는이시스템을구성하는클래스들을보여준다. HolidayRequest Class Fields Properties Approved From To IHolidayRequestValidator Interface Methods CanGrant HolidayRequestService Class Methods HolidayRequestService Submit IHolidayRequestReposityory Interface Methods Save 그림 4-9 테스트코드를작성하기에앞서그림 4-9에나타난클래스들을먼저구현해야한다. 1. Visual Studio를실행하고 ProEnt.Chap4.Mocking이라는이름의새솔루션을생성한다. 2. 솔루션탐색기에서솔루션항목을마우스오른쪽버튼으로클릭하고 [ 추가 새프로젝트 ] 메뉴를선택하여 ProEnt.Chap4.Mocking.Model이라는이름의클래스라이브러리프로젝트를추가한다. 3. 2번항목과같은방법으로 ProEnt.Chap4.Mocking.Model.Tests라는이름의두번째클래스라이브러리항목을추가한다.
59 테스트주도개발환경에서의존성처리하기 모든프로젝트를생성했으면솔루션항목을마우스오른쪽버튼으로클릭하고, [Windows 탐색기에서폴더열기 ] 메뉴를클릭하여 Windows 탐색기를실행한다. 솔루션폴더가열리면 lib이라는이름의폴더를새로생성하고, Nunit.framework.dll 파일을 NUnit 디렉터리에서 ( 기본적으로 %systemdrive%\%programfiles directory%\nunit 2.4.8\bin 폴더에위치하고있다 ) 복사하여새로생성한 lib 폴더에붙여넣는다. 5. Visual Studio 의솔루션탐색기에서솔루션항목을마우스오른쪽버튼으로클릭하고, [ 추가 새솔루션폴더 ] 메뉴를선택하여솔루션에 lib 이라는이름의새솔루션폴더를추가한다. 6. lib 솔루션폴더를마우스오른쪽버튼으로클릭하고, [ 추가 기존항목추가 ] 메뉴를선택한후솔루션의루트에위치하는 lib 폴더를찾아 NUnit.framework.dll 파일을추가한다. 7. ProEnt.Chap4.Model.Tests 프로젝트를마우스오른쪽버튼으로클릭하고, [ 참조추가 ] 메뉴를선택하여 NUnit.framework.dll 파일에대한참조를추가한다. 참조추가대화상자가나타나면 [ 찾아보기 ] 탭을선택하고, Lib 폴더를탐색한후 NUnit.framework.dll 파일을선택한다. 8. ProEnt.Chap4.Mocking.Model.Tests 프로젝트에 ProEnt.Chap4.Mocking.Model 프로젝트에대한참조를추가한다. 9. ProEnt.Chap4.Mocking.Model 프로젝트에 HolidayRequset라는이름의새클래스를추가하고다음의코드를작성한다. 이클래스는휴가요청자체를표현한다. namespace ProEnt.Chap4.Mocking.Model public class HolidayRequest private DateTime _from; private DateTime _to; private string _employeeid; private bool _approved; public DateTime From get return _from; set _from = value; public DateTime To
Microsoft PowerPoint - chap01-C언어개요.pptx
#include int main(void) { int num; printf( Please enter an integer: "); scanf("%d", &num); if ( num < 0 ) printf("is negative.\n"); printf("num = %d\n", num); return 0; } 1 학습목표 프로그래밍의 기본 개념을
More informationJUNIT 실습및발표
JUNIT 실습및발표 JUNIT 접속 www.junit.org DownLoad JUnit JavaDoc API Document 를참조 JUNIT 4.8.1 다운로드 설치파일 (jar 파일 ) 을다운로드 CLASSPATH 를설정 환경변수에서설정 실행할클래스에서 import JUnit 설치하기 테스트실행주석 @Test Test 를실행할 method 앞에붙임 expected
More informationWindows 8에서 BioStar 1 설치하기
/ 콘텐츠 테이블... PC에 BioStar 1 설치 방법... Microsoft SQL Server 2012 Express 설치하기... Running SQL 2012 Express Studio... DBSetup.exe 설정하기... BioStar 서버와 클라이언트 시작하기... 1 1 2 2 6 7 1/11 BioStar 1, Windows 8 BioStar
More informationMicrosoft PowerPoint - CSharp-10-예외처리
10 장. 예외처리 예외처리개념 예외처리구문 사용자정의예외클래스와예외전파 순천향대학교컴퓨터학부이상정 1 예외처리개념 순천향대학교컴퓨터학부이상정 2 예외처리 오류 컴파일타임오류 (Compile-Time Error) 구문오류이기때문에컴파일러의구문오류메시지에의해쉽게교정 런타임오류 (Run-Time Error) 디버깅의절차를거치지않으면잡기어려운심각한오류 시스템에심각한문제를줄수도있다.
More informationMicrosoft PowerPoint Android-SDK설치.HelloAndroid(1.0h).pptx
To be an Android Expert 문양세강원대학교 IT 대학컴퓨터학부 Eclipse (IDE) JDK Android SDK with ADT IDE: Integrated Development Environment JDK: Java Development Kit (Java SDK) ADT: Android Development Tools 2 JDK 설치 Eclipse
More informationMicrosoft PowerPoint - chap02-C프로그램시작하기.pptx
#include int main(void) { int num; printf( Please enter an integer "); scanf("%d", &num); if ( num < 0 ) printf("is negative.\n"); printf("num = %d\n", num); return 0; } 1 학습목표 을 작성하면서 C 프로그램의
More informationMicrosoft Word - ntasFrameBuilderInstallGuide2.5.doc
NTAS and FRAME BUILDER Install Guide NTAS and FRAME BUILDER Version 2.5 Copyright 2003 Ari System, Inc. All Rights reserved. NTAS and FRAME BUILDER are trademarks or registered trademarks of Ari System,
More informationJAVA 프로그래밍실습 실습 1) 실습목표 - 메소드개념이해하기 - 매개변수이해하기 - 새메소드만들기 - Math 클래스의기존메소드이용하기 ( ) 문제 - 직사각형모양의땅이있다. 이땅의둘레, 면적과대각
JAVA 프로그래밍실습 실습 1) 실습목표 - 메소드개념이해하기 - 매개변수이해하기 - 새메소드만들기 - Math 클래스의기존메소드이용하기 ( http://java.sun.com/javase/6/docs/api ) 문제 - 직사각형모양의땅이있다. 이땅의둘레, 면적과대각선의길이를계산하는메소드들을작성하라. 직사각형의가로와세로의길이는주어진다. 대각선의길이는 Math클래스의적절한메소드를이용하여구하라.
More informationPowerPoint Presentation
2014 년 5 월죽기전에테스트할것인가, 죽고나서테스트할것인가! Session 1 단위테스트, 그는적인가아군인가? - SimpleSoft 유경상수석컨설턴트 시작하기앞서 단위테스트 (Unit Test) 란? 정의 컴퓨터프로그래밍에서소스코드의특정모듈이의도된대로정확히작동하는지검증하는절차 ( 출처 : 위키백과 ) 주체 개발자 테스터 대상 프로그램소스코드 단위테스트는개발자의적인가아군인가?
More informationISP and CodeVisionAVR C Compiler.hwp
USBISP V3.0 & P-AVRISP V1.0 with CodeVisionAVR C Compiler http://www.avrmall.com/ November 12, 2007 Copyright (c) 2003-2008 All Rights Reserved. USBISP V3.0 & P-AVRISP V1.0 with CodeVisionAVR C Compiler
More informationView Licenses and Services (customer)
빠른 빠른 시작: 시작: 라이선스, 라이선스, 서비스 서비스 및 주문 주문 이력 이력 보기 보기 고객 가이드 Microsoft 비즈니스 센터의 라이선스, 서비스 및 혜택 섹션을 통해 라이선스, 온라인 서비스, 구매 기록 (주문 기록)을 볼 수 있습니다. 시작하려면, 비즈니스 센터에 로그인하여 상단 메뉴에서 재고를 선택한 후 내 재고 관리를 선택하십시오. 목차
More information다른 JSP 페이지호출 forward() 메서드 - 하나의 JSP 페이지실행이끝나고다른 JSP 페이지를호출할때사용한다. 예 ) <% RequestDispatcher dispatcher = request.getrequestdispatcher(" 실행할페이지.jsp");
다른 JSP 페이지호출 forward() 메서드 - 하나의 JSP 페이지실행이끝나고다른 JSP 페이지를호출할때사용한다. 예 ) RequestDispatcher dispatcher = request.getrequestdispatcher(" 실행할페이지.jsp"); dispatcher.forward(request, response); - 위의예에서와같이 RequestDispatcher
More informationgnu-lee-oop-kor-lec06-3-chap7
어서와 Java 는처음이지! 제 7 장상속 Super 키워드 상속과생성자 상속과다형성 서브클래스의객체가생성될때, 서브클래스의생성자만호출될까? 아니면수퍼클래스의생성자도호출되는가? class Base{ public Base(String msg) { System.out.println("Base() 생성자 "); ; class Derived extends Base
More informationq 이장에서다룰내용 1 객체지향프로그래밍의이해 2 객체지향언어 : 자바 2
객체지향프로그래밍 IT CookBook, 자바로배우는쉬운자료구조 q 이장에서다룰내용 1 객체지향프로그래밍의이해 2 객체지향언어 : 자바 2 q 객체지향프로그래밍의이해 v 프로그래밍기법의발달 A 군의사업발전 1 단계 구조적프로그래밍방식 3 q 객체지향프로그래밍의이해 A 군의사업발전 2 단계 객체지향프로그래밍방식 4 q 객체지향프로그래밍의이해 v 객체란무엇인가
More informationPowerPoint Presentation
Class - Property Jo, Heeseung 목차 section 1 클래스의일반구조 section 2 클래스선언 section 3 객체의생성 section 4 멤버변수 4-1 객체변수 4-2 클래스변수 4-3 종단 (final) 변수 4-4 멤버변수접근방법 section 5 멤버변수접근한정자 5-1 public 5-2 private 5-3 한정자없음
More information금오공대 컴퓨터공학전공 강의자료
C 프로그래밍프로젝트 Chap 14. 포인터와함수에대한이해 2013.10.09. 오병우 컴퓨터공학과 14-1 함수의인자로배열전달 기본적인인자의전달방식 값의복사에의한전달 val 10 a 10 11 Department of Computer Engineering 2 14-1 함수의인자로배열전달 배열의함수인자전달방식 배열이름 ( 배열주소, 포인터 ) 에의한전달 #include
More information슬라이드 제목 없음
MS SQL Server 마이크로소프트사가윈도우운영체제를기반으로개발한관계 DBMS 모바일장치에서엔터프라이즈데이터시스템에이르는다양한플랫폼에서운영되는통합데이터관리및분석솔루션 2 MS SQL Server 개요 3.1 MS SQL Server 개요 클라이언트-서버모델을기반으로하는관계 DBMS 로서윈도우계열의운영체제에서만동작함 오라클관계 DBMS 보다가격이매우저렴한편이고,
More informationC++ Programming
C++ Programming 예외처리 Seo, Doo-okok clickseo@gmail.com http://www.clickseo.com 목 차 예외처리 2 예외처리 예외처리 C++ 의예외처리 예외클래스와객체 3 예외처리 예외를처리하지않는프로그램 int main() int a, b; cout > a >> b; cout
More information오버라이딩 (Overriding)
WindowEvent WindowEvent 윈도우가열리거나 (opened) 닫힐때 (closed) 활성화되거나 (activated) 비활성화될때 (deactivated) 최소화되거나 (iconified) 복귀될때 (deiconified) 윈도우닫힘버튼을누를때 (closing) WindowEvent 수신자 abstract class WindowListener
More informationMVVM 패턴의 이해
Seo Hero 요약 joshua227.tistory. 2014 년 5 월 13 일 이문서는 WPF 어플리케이션개발에필요한 MVVM 패턴에대한내용을담고있다. 1. Model-View-ViewModel 1.1 기본개념 MVVM 모델은 MVC(Model-View-Contorl) 패턴에서출발했다. MVC 패턴은전체 project 를 model, view 로나누어
More information쉽게 풀어쓴 C 프로그래밍
제 5 장생성자와접근제어 1. 객체지향기법을이해한다. 2. 클래스를작성할수있다. 3. 클래스에서객체를생성할수있다. 4. 생성자를이용하여객체를초기화할수 있다. 5. 접근자와설정자를사용할수있다. 이번장에서만들어볼프로그램 생성자 생성자 (constructor) 는초기화를담당하는함수 생성자가필요한이유 #include using namespace
More informationMicrosoft PowerPoint - Java7.pptx
HPC & OT Lab. 1 HPC & OT Lab. 2 실습 7 주차 Jin-Ho, Jang M.S. Hanyang Univ. HPC&OT Lab. jinhoyo@nate.com HPC & OT Lab. 3 Component Structure 객체 (object) 생성개념을이해한다. 외부클래스에대한접근방법을이해한다. 접근제어자 (public & private)
More information<4D F736F F F696E74202D20C1A63038C0E520C5ACB7A1BDBABFCD20B0B4C3BC4928B0ADC0C729205BC8A3C8AF20B8F0B5E55D>
Power Java 제 8 장클래스와객체 I 이번장에서학습할내용 클래스와객체 객체의일생직접 메소드클래스를 필드작성해 UML 봅시다. QUIZ 1. 객체는 속성과 동작을가지고있다. 2. 자동차가객체라면클래스는 설계도이다. 먼저앞장에서학습한클래스와객체의개념을복습해봅시다. 클래스의구성 클래스 (class) 는객체의설계도라할수있다. 클래스는필드와메소드로이루어진다.
More informationPowerPoint Template
JavaScript 회원정보 입력양식만들기 HTML & JavaScript Contents 1. Form 객체 2. 일반적인입력양식 3. 선택입력양식 4. 회원정보입력양식만들기 2 Form 객체 Form 객체 입력양식의틀이되는 태그에접근할수있도록지원 Document 객체의하위에위치 속성들은모두 태그의속성들의정보에관련된것
More information경우 1) 80GB( 원본 ) => 2TB( 복사본 ), 원본 80GB 는 MBR 로디스크초기화하고 NTFS 로포맷한경우 복사본 HDD 도 MBR 로디스크초기화되고 80GB 만큼포맷되고나머지영역 (80GB~ 나머지부분 ) 은할당되지않음 으로나온다. A. Window P
Duplicator 는기본적으로원본하드디스크를빠르게복사본하드디스크에복사하는기능을하는것입니다.. 복사본 하드디스크가원본하드디스크와똑같게하는것을목적으로하는것이어서저용량에서고용량으로복사시몇 가지문제점이발생할수있습니다. 하드디스크는사용하려면, 디스크초기화를한후에포맷을해야사용가능합니다. Windows PC는 MBR과 GPT 2 개중에 1개로초기화합니다. -Windows
More informationUnitTesting(ÇѱÛÆÇ).hwp
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.
More information아이콘의 정의 본 사용자 설명서에서는 다음 아이콘을 사용합니다. 참고 참고는 발생할 수 있는 상황에 대처하는 방법을 알려 주거나 다른 기능과 함께 작동하는 방법에 대한 요령을 제공합니다. 상표 Brother 로고는 Brother Industries, Ltd.의 등록 상
Android 용 Brother Image Viewer 설명서 버전 0 KOR 아이콘의 정의 본 사용자 설명서에서는 다음 아이콘을 사용합니다. 참고 참고는 발생할 수 있는 상황에 대처하는 방법을 알려 주거나 다른 기능과 함께 작동하는 방법에 대한 요령을 제공합니다. 상표 Brother 로고는 Brother Industries, Ltd.의 등록 상표입니다. Android는
More informationC# Programming Guide - Types
C# Programming Guide - Types 최도경 lifeisforu@wemade.com 이문서는 MSDN 의 Types 를요약하고보충한것입니다. http://msdn.microsoft.com/enus/library/ms173104(v=vs.100).aspx Types, Variables, and Values C# 은 type 에민감한언어이다. 모든
More information유니티 변수-함수.key
C# 1 or 16 (Binary or Hex) 1:1 C# C# (Java, Python, Go ) (0101010 ). (Variable) : (Value) (Variable) : (Value) ( ) (Variable) : (Value) ( ) ; (Variable) : (Value) ( ) ; = ; (Variable) : (Value) (Variable)
More informationPowerPoint Presentation
객체지향프로그래밍 클래스, 객체, 메소드 ( 실습 ) 손시운 ssw5176@kangwon.ac.kr 예제 1. 필드만있는클래스 텔레비젼 2 예제 1. 필드만있는클래스 3 예제 2. 여러개의객체생성하기 4 5 예제 3. 메소드가추가된클래스 public class Television { int channel; // 채널번호 int volume; // 볼륨 boolean
More informationAPI - Notification 메크로를통하여어느특정상황이되었을때 SolidWorks 및보낸경로를통하여알림메시지를보낼수있습니다. 이번기술자료에서는메크로에서이벤트처리기를통하여진행할예정이며, 메크로에서작업을수행하는데유용할것입니다. 알림이벤트핸들러는응용프로그램구현하는데있어
메크로를통하여어느특정상황이되었을때 SolidWorks 및보낸경로를통하여알림메시지를보낼수있습니다. 이번기술자료에서는메크로에서이벤트처리기를통하여진행할예정이며, 메크로에서작업을수행하는데유용할것입니다. 알림이벤트핸들러는응용프로그램구현하는데있어서가장중요한부분이라고도할수있기때문입니다. 1. 새로운메크로생성 새메크로만들기버튺을클릭하여파일을생성합니다. 2. 메크로저장 -
More informationStuduino소프트웨어 설치
Studuino 프로그래밍환경 Studuino 소프트웨어설치 본자료는 Studuino 프로그래밍환경설치안내서입니다. Studuino 프로그래밍 환경의갱신에따라추가 / 수정될수있습니다. 목차 1. 소개... 1 2. Windows... 2 2.1. 프로그래밍환경설치... 2 2.1.1. 웹설치버전설치방법... 2 2.2. Studuino 프로그래밍환경실행...
More information윈도우시스템프로그래밍
데이터베이스및설계 MySQL 을위한 MFC 를사용한 ODBC 프로그래밍 2012.05.10. 오병우 컴퓨터공학과금오공과대학교 http://www.apmsetup.com 또는 http://www.mysql.com APM Setup 설치발표자료참조 Department of Computer Engineering 2 DB 에속한테이블보기 show tables; 에러발생
More informationvRealize Automation용 VMware Remote Console - VMware
vrealize Automation 용 VMware Remote Console VMware Remote Console 9.0 이문서는새버전으로교체되기전까지나열된각제품버전및모든이후버전을지원합니다. 이문서에대한최신버전을확인하려면 http://www.vmware.com/kr/support/pubs 를참조하십시오. KO-002230-00 vrealize Automation
More information2 단계 : 추상화 class 오리 { class 청둥오리 extends 오리 { class 물오리 extends 오리 { 청둥오리 mallardduck = new 청둥오리 (); 물오리 redheadduck = new 물오리 (); mallardduck.swim();
인터페이스적용 오리객체설계하기 ) 청둥오리, 물오리를설계하세요. 1 단계 : 필요한객체설계 class 청둥오리 { class 물오리 { 청둥오리 mallardduck = new 청둥오리 (); 물오리 redheadduck = new 물오리 (); mallardduck.swim(); mallardduck.fly(); mallardduck.quack(); redheadduck.swim();
More information목차 1. 시스템요구사항 암호및힌트설정 ( 윈도우 ) JetFlash Vault 시작하기 ( 윈도우 ) JetFlash Vault 옵션 ( 윈도우 )... 9 JetFlash Vault 설정... 9 JetFlash Vault
사용자매뉴얼 JetFlash Vault 100 ( 버전 1.0) 1 목차 1. 시스템요구사항... 3 2. 암호및힌트설정 ( 윈도우 )... 3 3. JetFlash Vault 시작하기 ( 윈도우 )... 7 4. JetFlash Vault 옵션 ( 윈도우 )... 9 JetFlash Vault 설정... 9 JetFlash Vault 찾아보기... 10 JetFlash
More information슬라이드 1
Software Verification #3 정적분석도구, 단위 / 시스템테스트도구 Software Verification Team 4 강 정 모 송 상 연 신 승 화 1 Software Verification #3 정적분석도구, 단위 / 시스템테스트도구 CONTENTS 01 Overall Structure 02 Static analyzer SonarQube
More informationJVM 메모리구조
조명이정도면괜찮조! 주제 JVM 메모리구조 설미라자료조사, 자료작성, PPT 작성, 보고서작성. 발표. 조장. 최지성자료조사, 자료작성, PPT 작성, 보고서작성. 발표. 조원 이용열자료조사, 자료작성, PPT 작성, 보고서작성. 이윤경 자료조사, 자료작성, PPT작성, 보고서작성. 이수은 자료조사, 자료작성, PPT작성, 보고서작성. 발표일 2013. 05.
More informationchap 5: Trees
5. Threaded Binary Tree 기본개념 n 개의노드를갖는이진트리에는 2n 개의링크가존재 2n 개의링크중에 n + 1 개의링크값은 null Null 링크를다른노드에대한포인터로대체 Threads Thread 의이용 ptr left_child = NULL 일경우, ptr left_child 를 ptr 의 inorder predecessor 를가리키도록변경
More informationMicrosoft PowerPoint - chap06-2pointer.ppt
2010-1 학기프로그래밍입문 (1) chapter 06-2 참고자료 포인터 박종혁 Tel: 970-6702 Email: jhpark1@snut.ac.kr 한빛미디어 출처 : 뇌를자극하는 C프로그래밍, 한빛미디어 -1- 포인터의정의와사용 변수를선언하는것은메모리에기억공간을할당하는것이며할당된이후에는변수명으로그기억공간을사용한다. 할당된기억공간을사용하는방법에는변수명외에메모리의실제주소값을사용하는것이다.
More informationPowerPoint Presentation
public class SumTest { public static void main(string a1[]) { int a, b, sum; a = Integer.parseInt(a1[0]); b = Integer.parseInt(a1[1]); sum = a + b ; // 두수를더하는부분입니다 System.out.println(" 두수의합은 " + sum +
More informationMicrosoft PowerPoint - C++ 5 .pptx
C++ 언어프로그래밍 한밭대학교전자. 제어공학과이승호교수 연산자중복 (operator overloading) 이란? 2 1. 연산자중복이란? 1) 기존에미리정의되어있는연산자 (+, -, /, * 등 ) 들을프로그래머의의도에맞도록새롭게정의하여사용할수있도록지원하는기능 2) 연산자를특정한기능을수행하도록재정의하여사용하면여러가지이점을가질수있음 3) 하나의기능이프로그래머의의도에따라바뀌어동작하는다형성
More informationJAVA PROGRAMMING 실습 08.다형성
2015 학년도 2 학기 1. 추상메소드 선언은되어있으나코드구현되어있지않은메소드 abstract 키워드사용 메소드타입, 이름, 매개변수리스트만선언 public abstract String getname(); public abstract void setname(string s); 2. 추상클래스 abstract 키워드로선언한클래스 종류 추상메소드를포함하는클래스
More information[ 마이크로프로세서 1] 2 주차 3 차시. 포인터와구조체 2 주차 3 차시포인터와구조체 학습목표 1. C 언어에서가장어려운포인터와구조체를설명할수있다. 2. Call By Value 와 Call By Reference 를구분할수있다. 학습내용 1 : 함수 (Functi
2 주차 3 차시포인터와구조체 학습목표 1. C 언어에서가장어려운포인터와구조체를설명할수있다. 2. Call By Value 와 Call By Reference 를구분할수있다. 학습내용 1 : 함수 (Function) 1. 함수의개념 입력에대해적절한출력을발생시켜주는것 내가 ( 프로그래머 ) 작성한명령문을연산, 처리, 실행해주는부분 ( 모듈 ) 자체적으로실행되지않으며,
More information<B3EDB9AEC0DBBCBAB9FD2E687770>
(1) 주제 의식의 원칙 논문은 주제 의식이 잘 드러나야 한다. 주제 의식은 논문을 쓰는 사람의 의도나 글의 목적 과 밀접한 관련이 있다. (2) 협력의 원칙 독자는 필자를 이해하려고 마음먹은 사람이다. 따라서 필자는 독자가 이해할 수 있는 말이 나 표현을 사용하여 독자의 노력에 협력해야 한다는 것이다. (3) 논리적 엄격성의 원칙 감정이나 독단적인 선언이
More informationMicrosoft Word - Armjtag_문서1.doc
ARM JTAG (wiggler 호환 ) 사용방법 ( IAR EWARM 에서 ARM-JTAG 로 Debugging 하기 ) Test Board : AT91SAM7S256 IAR EWARM : Kickstart for ARM ARM-JTAG : ver 1.0 ( 씨링크테크 ) 1. IAR EWARM (Kickstart for ARM) 설치 2. Macraigor
More information설계란 무엇인가?
금오공과대학교 C++ 프로그래밍 jhhwang@kumoh.ac.kr 컴퓨터공학과 황준하 6 강. 함수와배열, 포인터, 참조목차 함수와포인터 주소값의매개변수전달 주소의반환 함수와배열 배열의매개변수전달 함수와참조 참조에의한매개변수전달 참조의반환 프로그래밍연습 1 /15 6 강. 함수와배열, 포인터, 참조함수와포인터 C++ 매개변수전달방법 값에의한전달 : 변수값,
More information학습목표 함수프로시저, 서브프로시저의의미를안다. 매개변수전달방식을학습한다. 함수를이용한프로그래밍한다. 2
학습목표 함수프로시저, 서브프로시저의의미를안다. 매개변수전달방식을학습한다. 함수를이용한프로그래밍한다. 2 6.1 함수프로시저 6.2 서브프로시저 6.3 매개변수의전달방식 6.4 함수를이용한프로그래밍 3 프로시저 (Procedure) 프로시저 (Procedure) 란무엇인가? 논리적으로묶여있는하나의처리단위 내장프로시저 이벤트프로시저, 속성프로시저, 메서드, 비주얼베이직내장함수등
More information1. 자바프로그램기초 및개발환경 2 장 & 3 장. 자바개발도구 충남대학교 컴퓨터공학과
1. 자바프로그램기초 및개발환경 2 장 & 3 장. 자바개발도구 충남대학교 컴퓨터공학과 학습내용 1. Java Development Kit(JDK) 2. Java API 3. 자바프로그래밍개발도구 (Eclipse) 4. 자바프로그래밍기초 2 자바를사용하려면무엇이필요한가? 자바프로그래밍개발도구 JDK (Java Development Kit) 다운로드위치 : http://www.oracle.com/technetwork/java/javas
More informationIP 심화 라우팅프로토콜적용시 라우팅테이블에서 이니셜이있는네트워크를설정하는것 : onnected 직접연결된네트워크를의미한다. 그러므로라우팅은 나는이런네트워크와연결되어있다. 를직접연결된라우터들에게알려주는것 1>en 1#conf t 1(config)#router rip 1
IP 심화 º 각 P 의게이트웨이는해당네트워크의마지막주소를사용한다. - P1 (210.220.10.1/26) 의게이트웨이 (5의 Fa0/0) : 210.220.10.63 /26 = 255.255.255.192 호스트비트수 : 32-26 = 6 비트 => = 64 그러므로 P1의 IP 210.220.10.1 중서브넷마스크에의거 26비트는변함이없고, 나머지 6비트가호스트비트로변하므로
More informationMicrosoft PowerPoint SDK설치.HelloAndroid(1.5h).pptx
To be an Android Expert 문양세강원대학교 IT 대학컴퓨터학부 개발환경구조및설치순서 JDK 설치 Eclipse 설치 안드로이드 SDK 설치 ADT(Androd Development Tools) 설치 AVD(Android Virtual Device) 생성 Hello Android! 2 Eclipse (IDE) JDK Android SDK with
More information제8장 자바 GUI 프로그래밍 II
제8장 MVC Model 8.1 MVC 모델 (1/7) MVC (Model, View, Controller) 모델 스윙은 MVC 모델에기초를두고있다. MVC란 Xerox의연구소에서 Smalltalk 언어를바탕으로사용자인터페이스를개발하기위한방법 MVC는 3개의구성요소로구성 Model : 응용프로그램의자료를표현하기위한모델 View : 자료를시각적으로 (GUI 방식으로
More information쉽게 풀어쓴 C 프로그래밊
Power Java 제 27 장데이터베이스 프로그래밍 이번장에서학습할내용 자바와데이터베이스 데이터베이스의기초 SQL JDBC 를이용한프로그래밍 변경가능한결과집합 자바를통하여데이터베이스를사용하는방법을학습합니다. 자바와데이터베이스 JDBC(Java Database Connectivity) 는자바 API 의하나로서데이터베이스에연결하여서데이터베이스안의데이터에대하여검색하고데이터를변경할수있게한다.
More informationVisual Basic 반복문
학습목표 반복문 For Next문, For Each Next문 Do Loop문, While End While문 구구단작성기로익히는반복문 2 5.1 반복문 5.2 구구단작성기로익히는반복문 3 반복문 주어진조건이만족하는동안또는주어진조건이만족할때까지일정구간의실행문을반복하기위해사용 For Next For Each Next Do Loop While Wend 4 For
More informationDBMS & SQL Server Installation Database Laboratory
DBMS & 조교 _ 최윤영 } 데이터베이스연구실 (1314 호 ) } 문의사항은 cyy@hallym.ac.kr } 과제제출은 dbcyy1@gmail.com } 수업공지사항및자료는모두홈페이지에서확인 } dblab.hallym.ac.kr } 홈페이지 ID: 학번 } 홈페이지 PW:s123 2 차례 } } 설치전점검사항 } 설치단계별설명 3 Hallym Univ.
More informationPowerPoint Presentation
객체지향프로그래밍 인터페이스, 람다식, 패키지 ( 실습 ) 손시운 ssw5176@kangwon.ac.kr 예제 1. 홈네트워킹 public interface RemoteControl { public void turnon(); // 가전제품을켠다. public void turnoff(); // 가전제품을끈다. 인터페이스를구현 public class Television
More informationadfasdfasfdasfasfadf
C 4.5 Source code Pt.3 ISL / 강한솔 2019-04-10 Index Tree structure Build.h Tree.h St-thresh.h 2 Tree structure *Concpets : Node, Branch, Leaf, Subtree, Attribute, Attribute Value, Class Play, Don't Play.
More information<4D F736F F F696E74202D C61645FB3EDB8AEC7D5BCBA20B9D720C5F8BBE7BFEBB9FD2E BC8A3C8AF20B8F0B5E55D>
VHDL 프로그래밍 D. 논리합성및 Xilinx ISE 툴사용법 학습목표 Xilinx ISE Tool 을이용하여 Xilinx 사에서지원하는해당 FPGA Board 에맞는논리합성과정을숙지 논리합성이가능한코드와그렇지않은코드를구분 Xilinx Block Memory Generator를이용한 RAM/ ROM 생성하는과정을숙지 2/31 Content Xilinx ISE
More informationC 프로그램의 기본
C 프로그램의기본 목차 C 프로그램의구성요소 주석 main 함수 출력 C 언어의입력과출력 변수 printf 함수 scanf 함수 2 예제 2-1 : 첫번째 C 프로그램 3 2.1.1 주석 주석의용도 프로그램에대한설명 프로그램전체에대한대략적인정보를제공 프로그램수행에영향을미치지않는요소 4 2.1.1 주석 주석사용방법 /* 과 */ 을이용한여러줄주석 // 을이용한한줄주석
More informationMicrosoft Word - src.doc
IPTV 서비스탐색및콘텐츠가이드 RI 시스템운용매뉴얼 목차 1. 서버설정방법... 5 1.1. 서비스탐색서버설정... 5 1.2. 컨텐츠가이드서버설정... 6 2. 서버운용방법... 7 2.1. 서비스탐색서버운용... 7 2.1.1. 서비스가이드서버실행... 7 2.1.2. 서비스가이드정보확인... 8 2.1.3. 서비스가이드정보추가... 9 2.1.4. 서비스가이드정보삭제...
More information<4D F736F F F696E74202D203137C0E55FBFACBDC0B9AEC1A6BCD6B7E7BCC72E707074>
SIMATIC S7 Siemens AG 2004. All rights reserved. Date: 22.03.2006 File: PRO1_17E.1 차례... 2 심벌리스트... 3 Ch3 Ex2: 프로젝트생성...... 4 Ch3 Ex3: S7 프로그램삽입... 5 Ch3 Ex4: 표준라이브러리에서블록복사... 6 Ch4 Ex1: 실제구성을 PG 로업로드하고이름변경......
More informationThisJava ..
자바언어에정확한타입을추가한 ThisJava 소개 나현익, 류석영 프로그래밍언어연구실 KAIST 2014 년 1 월 14 일 나현익, 류석영 자바언어에정확한타입을추가한 ThisJava 소개 1/29 APLAS 2013 나현익, 류석영 자바 언어에 정확한 타입을 추가한 ThisJava 소개 2/29 실제로부딪힌문제 자바스크립트프로그램분석을위한요약도메인 나현익,
More informationMicrosoft PowerPoint - jfeature장범석서재원박동현.pptm
소프트웨어검증 J F JFeature REQUIREMENT COVERAGE TOOL 장범석서재원박동현 순서 1. JFeature 소개 2. JFeature 사용 3. JFeature VS OSRMT 4. 프로젝트적용방안 1. JFeature 소개 1. JFeature 소개 JFeature Feature/requirement coverage tool 개발하는코드에해당하는요구사항에초점
More informationPowerPoint 프레젠테이션
인터페이스 배효철 th1g@nate.com 1 목차 인터페이스의역할 인터페이스선언 인터페이스구현 인터페이스사용 타입변환과다형성 인터페이스상속 디폴트메소드와인터페이스확장 2 인터페이스의역할 인터페이스란? 개발코드와객체가서로통신하는접점 개발코드는인터페이스의메소드만알고있으면 OK 인터페이스의역할 개발코드가객체에종속되지않게 -> 객체교체할수있도록하는역할 개발코드변경없이리턴값또는실행내용이다양해질수있음
More informationChapter 4. LISTS
C 언어에서리스트구현 리스트의생성 struct node { int data; struct node *link; ; struct node *ptr = NULL; ptr = (struct node *) malloc(sizeof(struct node)); Self-referential structure NULL: defined in stdio.h(k&r C) or
More informationMicrosoft PowerPoint - 3장-MS SQL Server.ppt [호환 모드]
MS SQL Server 마이크로소프트사가윈도우운영체제를기반으로개발한관계 DBMS 모바일장치에서엔터프라이즈데이터시스템에이르는다양한플랫폼에서운영되는통합데이터관리및분석솔루션 2 MS SQL Server 개요 3.1 MS SQL Server 개요 클라이언트-서버모델을기반으로하는관계 DBMS로서윈도우계열의운영체제에서만동작함 오라클관계 DBMS보다가격이매우저렴한편이고,
More informationSpring Boot/JDBC JdbcTemplate/CRUD 예제
Spring Boot/JDBC JdbcTemplate/CRUD 예제 오라클자바커뮤니티 (ojc.asia, ojcedu.com) Spring Boot, Gradle 과오픈소스인 MariaDB 를이용해서 EMP 테이블을만들고 JdbcTemplate, SimpleJdbcTemplate 을이용하여 CRUD 기능을구현해보자. 마리아 DB 설치는다음 URL 에서확인하자.
More informationInsertColumnNonNullableError(#colName) 에해당하는메시지출력 존재하지않는컬럼에값을삽입하려고할경우, InsertColumnExistenceError(#colName) 에해당하는메시지출력 실행결과가 primary key 제약에위배된다면, Ins
Project 1-3: Implementing DML Due: 2015/11/11 (Wed), 11:59 PM 이번프로젝트의목표는프로젝트 1-1 및프로젝트 1-2에서구현한프로그램에기능을추가하여간단한 DML을처리할수있도록하는것이다. 구현한프로그램은 3개의 DML 구문 (insert, delete, select) 을처리할수있어야한다. 테이블데이터는파일에저장되어프로그램이종료되어도사라지지않아야한다.
More informationPowerPoint Presentation
자바프로그래밍 1 배열 손시운 ssw5176@kangwon.ac.kr 배열이필요한이유 예를들어서학생이 10 명이있고성적의평균을계산한다고가정하자. 학생 이 10 명이므로 10 개의변수가필요하다. int s0, s1, s2, s3, s4, s5, s6, s7, s8, s9; 하지만만약학생이 100 명이라면어떻게해야하는가? int s0, s1, s2, s3, s4,
More information쉽게
Power Java 제 4 장자바프로그래밍기초 이번장에서학습할내용 자바프로그램에대한기초사항을학습 자세한내용들은추후에. Hello.java 프로그램 주석 주석 (comment): 프로그램에대한설명을적어넣은것 3 가지타입의주석 클래스 클래스 (class): 객체를만드는설계도 ( 추후에학습 ) 자바프로그램은클래스들로구성된다. 그림 4-1. 자바프로그램의구조 클래스정의
More information< 목차 > Ⅰ. 개요 3 Ⅱ. 실시간스팸차단리스트 (RBL) ( 간편설정 ) 4 1. 메일서버 (Exchange Server 2007) 설정변경 4 2. 스팸차단테스트 10
(https://www.kisarbl.or.kr) < 목차 > Ⅰ. 개요 3 Ⅱ. 실시간스팸차단리스트 (RBL) ( 간편설정 ) 4 1. 메일서버 (Exchange Server 2007) 설정변경 4 2. 스팸차단테스트 10 Ⅰ. 개요 실시간스팸차단리스트 (RBL) 는메일서버를운영하는누구나손쉽게효과적으로스팸수신을차단하는데이용할수있도록한국인터넷진흥원 (KISA)
More information제이쿼리 (JQuery) 정의 자바스크립트함수를쉽게사용하기위해만든자바스크립트라이브러리. 웹페이지를즉석에서변경하는기능에특화된자바스크립트라이브러리. 사용법 $( 제이쿼리객체 ) 혹은 $( 엘리먼트 ) 참고 ) $() 이기호를제이쿼리래퍼라고한다. 즉, 제이쿼리를호출하는기호
제이쿼리 () 정의 자바스크립트함수를쉽게사용하기위해만든자바스크립트라이브러리. 웹페이지를즉석에서변경하는기능에특화된자바스크립트라이브러리. 사용법 $( 제이쿼리객체 ) 혹은 $( 엘리먼트 ) 참고 ) $() 이기호를제이쿼리래퍼라고한다. 즉, 제이쿼리를호출하는기호 CSS와마찬가지로, 문서에존재하는여러엘리먼트를접근할수있다. 엘리먼트접근방법 $( 엘리먼트 ) : 일반적인접근방법
More information1. 객체의생성과대입 int 형변수 : 선언과동시에초기화하는방법 (C++) int a = 3; int a(3); // 기본타입역시클래스와같이처리가능 객체의생성 ( 복습 ) class CPoint private : int x, y; public : CPoint(int a
6 장복사생성자 객체의생성과대입객체의값에의한전달복사생성자디폴트복사생성자복사생성자의재정의객체의값에의한반환임시객체 C++ 프로그래밍입문 1. 객체의생성과대입 int 형변수 : 선언과동시에초기화하는방법 (C++) int a = 3; int a(3); // 기본타입역시클래스와같이처리가능 객체의생성 ( 복습 ) class CPoint private : int x, y;
More informationMicrosoft Word - 3부A windows 환경 IVF + visual studio.doc
Visual Studio 2005 + Intel Visual Fortran 9.1 install Intel Visual Fortran 9.1 intel Visual Fortran Compiler 9.1 만설치해서 DOS 모드에서실행할수있지만, Visual Studio 2005 의 IDE 를사용하기위해서는 Visual Studio 2005 를먼저설치후 Integration
More information작성자 : 김성박\(삼성 SDS 멀티캠퍼스 전임강사\)
Session 을이용한현재로그인한사용자의 숫자구하기 작성자 : 김성박 ( 삼성 SDS 멀티캠퍼스전임강사 ) email : urstory@nownuri.net homepage : http://sunny.sarang.net - 본문서는http://sunny.sarang.net JAVA강좌란 혹은 http://www.javastudy.co.kr 의 칼럼 란에서만배포합니다.
More informationMicrosoft PowerPoint - additional01.ppt [호환 모드]
1.C 기반의 C++ part 1 함수 오버로딩 (overloading) 디폴트매개변수 (default parameter) 인-라인함수 (in-line function) 이름공간 (namespace) Jong Hyuk Park 함수 Jong Hyuk Park 함수오버로딩 (overloading) 함수오버로딩 (function overloading) C++ 언어에서는같은이름을가진여러개의함수를정의가능
More information11장 포인터
누구나즐기는 C 언어콘서트 제 9 장포인터 이번장에서학습할내용 포인터이란? 변수의주소 포인터의선언 간접참조연산자 포인터연산 포인터와배열 포인터와함수 이번장에서는포인터의기초적인지식을학습한다. 포인터란? 포인터 (pointer): 주소를가지고있는변수 메모리의구조 변수는메모리에저장된다. 메모리는바이트단위로액세스된다. 첫번째바이트의주소는 0, 두번째바이트는 1, 변수와메모리
More information윈도우시스템프로그래밍
데이타베이스 MySQL 을위한 MFC 를사용한 ODBC 프로그래밍 2013.05.15. 오병우 컴퓨터공학과금오공과대학교 http://www.apmsetup.com 또는 http://www.mysql.com APM Setup 설치발표자료참조 Department of Computer Engineering 2 DB 에속한테이블보기 show tables; 에러발생
More informationJDK이클립스
JDK 와이클립스설치 A. JDK 다운로드, 설치및환경설정 지금부터 JDK를다운로드받아설치하고 JDK를윈도우에서활용할수있도록환경을설정하는전과정을소개한다. 다운로드 www.oracle.com 사이트에접속하여 Downloads 메뉴를선택한후 [ 그림 1] 과같이 "Java for Developers" 를클릭한다. [ 그림 1] www.oracle.com 사이트
More information슬라이드 1
핚국산업기술대학교 제 14 강 GUI (III) 이대현교수 학습안내 학습목표 CEGUI 라이브러리를이용하여, 게임메뉴 UI 를구현해본다. 학습내용 CEGUI 레이아웃의로딩및렌더링. OIS 와 CEGUI 의연결. CEGUI 위젯과이벤트의연동. UI 구현 : 하드코딩방식 C++ 코드를이용하여, 코드내에서직접위젯들을생성및설정 CEGUI::PushButton* resumebutton
More informationMicrosoft PowerPoint - ch07 - 포인터 pm0415
2015-1 프로그래밍언어 7. 포인터 (Pointer), 동적메모리할당 2015 년 4 월 4 일 교수김영탁 영남대학교공과대학정보통신공학과 (Tel : +82-53-810-2497; Fax : +82-53-810-4742 http://antl.yu.ac.kr/; E-mail : ytkim@yu.ac.kr) Outline 포인터 (pointer) 란? 간접참조연산자
More informationPowerPoint 프레젠테이션
실습 1 배효철 th1g@nate.com 1 목차 조건문 반복문 System.out 구구단 모양만들기 Up & Down 2 조건문 조건문의종류 If, switch If 문 조건식결과따라중괄호 { 블록을실행할지여부결정할때사용 조건식 true 또는 false값을산출할수있는연산식 boolean 변수 조건식이 true이면블록실행하고 false 이면블록실행하지않음 3
More informationEndpoint Protector - Active Directory Deployment Guide
Version 1.0.0.1 Active Directory 배포가이드 I Endpoint Protector Active Directory Deployment Guide 목차 1. 소개...1 2. WMI 필터생성... 2 3. EPP 배포 GPO 생성... 9 4. 각각의 GPO 에해당하는 WMI 연결... 12 5.OU 에 GPO 연결... 14 6. 중요공지사항
More information4S 1차년도 평가 발표자료
모바일 S/W 프로그래밍 안드로이드개발환경설치 2012.09.05. 오병우 모바일공학과 JDK (Java Development Kit) SE (Standard Edition) 설치순서 Eclipse ADT (Android Development Tool) Plug-in Android SDK (Software Development Kit) SDK Components
More informationPowerPoint Presentation
Software Verification T4 고수창전소영이세라하지윤 Index 1 CI 2 IntelliJ IDEA 3 JUnit 4 Build Environment 5 Git 1 Continuous Integration What is CI? 소프트웨어개발에서 Build/Test 의프로세스를지속적으로수행하는것 개발자생산성향상 버그의빠른발견및해결 더빠른업데이트제공
More informationMicrosoft PowerPoint - e pptx
Import/Export Data Using VBA Objectives Referencing Excel Cells in VBA Importing Data from Excel to VBA Using VBA to Modify Contents of Cells 새서브프로시저작성하기 프로시저실행하고결과확인하기 VBA 코드이해하기 Referencing Excel Cells
More information슬라이드 1
-Part3- 제 4 장동적메모리할당과가변인 자 학습목차 4.1 동적메모리할당 4.1 동적메모리할당 4.1 동적메모리할당 배울내용 1 프로세스의메모리공간 2 동적메모리할당의필요성 4.1 동적메모리할당 (1/6) 프로세스의메모리구조 코드영역 : 프로그램실행코드, 함수들이저장되는영역 스택영역 : 매개변수, 지역변수, 중괄호 ( 블록 ) 내부에정의된변수들이저장되는영역
More information슬라이드 1
- 1 - 전자정부모바일표준프레임워크실습 LAB 개발환경 실습목차 LAB 1-1 모바일프로젝트생성실습 LAB 1-2 모바일사이트템플릿프로젝트생성실습 LAB 1-3 모바일공통컴포넌트생성및조립도구실습 - 2 - LAB 1-1 모바일프로젝트생성실습 (1/2) Step 1-1-01. 구현도구에서 egovframe>start>new Mobile Project 메뉴를선택한다.
More information노트북 IT / 모바일 데스크탑 34 올인원PC 35 PC 소프트웨어 포터블SSD / SSD / 메모리카드 36 태블릿 37 휴대폰 39 PC 솔루션 IT / 모바일 IT / 모바일 노트북 29 삼성전자는 Windows 를 권장합니다. 삼성전자만의 편리하고 다양한 소프트웨어를 통해 초보자도 보다 쉽고 빠르게 이용 가능합니다. Easy Settings 삼성 패스트
More informationMicrosoft PowerPoint - ch09 - 연결형리스트, Stack, Queue와 응용 pm0100
2015-1 프로그래밍언어 9. 연결형리스트, Stack, Queue 2015 년 5 월 4 일 교수김영탁 영남대학교공과대학정보통신공학과 (Tel : +82-53-810-2497; Fax : +82-53-810-4742 http://antl.yu.ac.kr/; E-mail : ytkim@yu.ac.kr) 연결리스트 (Linked List) 연결리스트연산 Stack
More information슬라이드 1
Gradle 1. 도구개요 2. 설치및실행 3. 주요기능 4. 활용예제 1. 도구개요 1.1 도구정보요약 도구명 소개 특징 Gradle (http://www.gradle.org) 소프트웨어빌드자동화도구 라이선스 Apache License v2.0 Gradle 을통해소프트웨어패키지나프로젝트의빌드, 테스팅, 퍼블리슁, 배포등을자동화할수있다. Ant 의유연성과기능을
More informationPowerPoint Presentation
객체지향프로그래밍 오류처리 손시운 ssw5176@kangwon.ac.kr 오류메시지를분석한다. 오류메시지에서많은내용을알수있다. 2 디버깅 디버거를사용하면프로그램에서쉽게오류를감지하고진단할수있다. 디버거는중단점을설정하여서프로그램의실행을제어할수있으며문장 단위로실행하거나변수의값을살펴볼수있다. 3 이클립스에서디버깅 4 이클립스에서디버깅 5 이클립스의디버깅명령어 6 예외처리
More information슬라이드 1
UNIT 16 예외처리 로봇 SW 교육원 3 기 최상훈 학습목표 2 예외처리구문 try-catch-finally 문을사용핛수있다. 프로그램오류 3 프로그램오류의종류 컴파일에러 (compile-time error) : 컴파일실행시발생 럮타임에러 (runtime error) : 프로그램실행시발생 에러 (error) 프로그램코드에의해서해결될수없는심각핚오류 ex)
More information쉽게 풀어쓴 C 프로그래밍
Power Java 제 7 장클래스와객체 이번장에서학습할내용 객체지향이란? 객체 메시지 클래스 객체지향의장점 String 클래스 객체지향개념을완벽하게이해해야만객체지향설계의이점을활용할수있다. 실제세계는객체로이루어진다. 객체지향이란? 실제세계를모델링하여소프트웨어를개발하는방법 절차지향과객체지향 절차지향프로그래밍 (procedural programming): 문제를해결하는절차를중요하게생각하는방법
More information학습목차 2.1 다차원배열이란 차원배열의주소와값의참조
- Part2- 제 2 장다차원배열이란무엇인가 학습목차 2.1 다차원배열이란 2. 2 2 차원배열의주소와값의참조 2.1 다차원배열이란 2.1 다차원배열이란 (1/14) 다차원배열 : 2 차원이상의배열을의미 1 차원배열과다차원배열의비교 1 차원배열 int array [12] 행 2 차원배열 int array [4][3] 행 열 3 차원배열 int array [2][2][3]
More information쉽게 풀어쓴 C 프로그래밍
제 3 장함수와문자열 1. 함수의기본적인개념을이해한다. 2. 인수와매개변수의개념을이해한다. 3. 함수의인수전달방법 2가지를이해한다 4. 중복함수를이해한다. 5. 디폴트매개변수를이해한다. 6. 문자열의구성을이해한다. 7. string 클래스의사용법을익힌다. 이번장에서만들어볼프로그램 함수란? 함수선언 함수호출 예제 #include using
More informationAPI 매뉴얼
PCI-DIO12 API Programming (Rev 1.0) Windows, Windows2000, Windows NT and Windows XP are trademarks of Microsoft. We acknowledge that the trademarks or service names of all other organizations mentioned
More informationOCW_C언어 기초
초보프로그래머를위한 C 언어기초 2 장 : C 프로그램시작하기 2012 년 이은주 학습목표 을작성하면서 C 프로그램의구성요소 주석 (comment) 이란무엇인지알아보고, 주석을만드는방법 함수란무엇인지알아보고, C 프로그램에반드시필요한 main 함수 C 프로그램에서출력에사용되는 printf 함수 변수의개념과변수의값을입력받는데사용되는 scanf 함수 2 목차 프로그램코드
More informationSystem Recovery 사용자 매뉴얼
Samsung OS Recovery Solution 을이용하여간편하게 MagicInfo 의네트워크를설정하고시스템을백업및복원할수있습니다. 시스템시작시리모컨의 - 버튼이나키보드의 F3 키를연속해서누르면복구모드로진입한후 Samsung OS Recovery Solution 이실행됩니다. Samsung OS Recovery Solution 은키보드와리모컨을사용하여조작할수있습니다.
More informationMulti-pass Sieve를 이용한 한국어 상호참조해결 반-자동 태깅 도구
Python: 파이썬프로그래밍의기초, 함수 Kangwon Natl. University Department of Computer Science Cheoneum Park Intelligent software Lab. 함수 Intelligent software Lab. 2 함수란무엇인가? Intelligent software Lab. 3 함수를사용하는이유는? 프로그래밍을하다보면똑같은내용을반복해서작성하는경우다반사
More information