[[TableOfContents]] == Example - Test First Programming 으로 만들어보는 Queue == 솔직히 Python도 처음이고 TFP 도 처음이여서 제대로 했다는 보장이 안된다. --; (특히, count 메소드를 먼저 잡았다는 점에서 두가지 Test Case를 만들었다는 점이 맘에 안든다. 추후에 다른 더 좋은 예제가 생기면 그때 바꿔버리던지 해야지. -_; === 준비. Queue를 만들거다. === ''TestCaseQueue.py'' {{{~cpp import unittest suite = unittest.makeSuite (QueueTestCase, "test") runner = unittest.TextTestRunner () runner.run (suite) }}} ''Queue.py'' {{{~cpp (없음) }}} === Queue다. 무엇을 하는 넘일까? === 무엇을 해야 할까... 일단 이녀석은 값을 enqueue하면 하나씩 저장될 것이다. 그러면 저장되는 갯수가 늘어날 것이다. === Construction... === ''TestCaseQueue.py'' {{{~cpp import unittest class QueueTestCase (unittest.TestCase): def testCount (self): q = Queue () q.enqueue (10) self.assertEquals (q.count(), 1) suite = unittest.makeSuite (QueueTestCase, "test") runner = unittest.TextTestRunner () runner.run (suite) }}} ''Queue.py'' {{{~cpp (없음) }}} ''결과'' {{{~cpp ====================================================================== ERROR: testCount (TestCaseQueue.QueueTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\USER\reset\TestCaseQueue.py", line 5, in testCount q = Queue () NameError: global name 'Queue' is not defined ---------------------------------------------------------------------- Ran 1 tests in 0.060s FAILED (errors=1) }}} Python 이 Queue 클래스를 요구하는군. Queue 클래스 만들라고 하니까 만들어주자. ''Queue.py'' {{{~cpp class Queue: pass }}} ''결과'' {{{~cpp ====================================================================== ERROR: testCount (TestCaseQueue.QueueTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\USER\reset\TestCaseQueue.py", line 7, in testCount q.enqueue (10) AttributeError: Queue instance has no attribute 'enqueue' ---------------------------------------------------------------------- Ran 1 tests in 0.000s FAILED (errors=1) }}} enqueue 가 없다고 한다. enqueue 도 채워주자. count 도 잠시나마 채워주자. ''Queue.py'' {{{~cpp class Queue: def enqueue (self, n): pass def count (self): return 0 }}} ''결과'' {{{~cpp ====================================================================== FAIL: testCount (TestCaseQueue.QueueTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\USER\reset\TestCaseQueue.py", line 8, in testCount self.assertEquals (q.count(), 1) File "C:\PYTHON22\lib\unittest.py", line 286, in failUnlessEqual raise self.failureException, \ AssertionError: 0 != 1 ---------------------------------------------------------------------- Ran 1 tests in 0.000s FAILED (failures=1) }}} count 가 안늘어나는군. 장난 칠까.. --a {{{~cpp class Queue: def enqueue (self, n): pass def count (self): return 1 }}} {{{~cpp ---------------------------------------------------------------------- Ran 1 tests in 0.060s OK }}} 그러면 다음과 같은 경우는? {{{~cpp import unittest from queue import Queue class QueueTestCase (unittest.TestCase): def testCount (self): q = Queue () q.enqueue (10) self.assertEquals (q.count(), 1) q.enqueue (20) self.assertEquals (q.count(), 2) q.enqueue (30) self.assertEquals (q.count(), 3) suite = unittest.makeSuite (QueueTestCase, "test") runner = unittest.TextTestRunner () runner.run (suite) }}} {{{~cpp ====================================================================== FAIL: testCount (TestCaseQueue.QueueTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\USER\reset\TestCaseQueue.py", line 10, in testCount suite = unittest.makeSuite (QueueTestCase, "test") File "C:\PYTHON22\lib\unittest.py", line 286, in failUnlessEqual raise self.failureException, \ AssertionError: 1 != 2 ---------------------------------------------------------------------- Ran 1 tests in 0.050s FAILED (failures=1) }}} 자. enqueue 를 만들고 count를 세어보자. {{{~cpp class Queue: def __init__ (self): self.qu_list = [] def enqueue (self, n): pass def count (self): return len (self.qu_list) }}} {{{~cpp ====================================================================== FAIL: testCount (TestCaseQueue.QueueTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\USER\reset\TestCaseQueue.py", line 8, in testCount self.assertEquals (q.count(), 1) File "C:\PYTHON22\lib\unittest.py", line 286, in failUnlessEqual raise self.failureException, \ AssertionError: 0 != 1 ---------------------------------------------------------------------- Ran 1 tests in 0.060s FAILED (failures=1) }}} enqueue를 보장하기 위한 테스트를 먼저 생각해보자. queue는 말 그대로 안에 들어가는 값이 하나하나 늘어난다. First Input First Out이다. {{{~cpp import unittest from queue import Queue class QueueTestCase (unittest.TestCase): def testEnqueue (self): q = Queue () q.enqueue (10) self.assertEquals (q.last(), 10) q.enqueue (20) self.assertEquals (q.last(), 20) def testCount (self): q = Queue () q.enqueue (10) self.assertEquals (q.count(), 1) q.enqueue (20) self.assertEquals (q.count(), 2) q.enqueue (30) self.assertEquals (q.count(), 3) suite = unittest.makeSuite (QueueTestCase, "test") runner = unittest.TextTestRunner () runner.run (suite) }}} {{{~cpp ====================================================================== ERROR: testEnqueue (TestCaseQueue.QueueTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\USER\reset\TestCaseQueue.py", line 8, in testEnqueue self.assertEquals (q.count(), 1) AttributeError: Queue instance has no attribute 'last' ---------------------------------------------------------------------- Ran 2 tests in 0.000s FAILED (errors=1) }}} last메소드를 만들어주자. {{{~cpp class Queue: def __init__ (self): self.qu_list = [] def enqueue (self, n): self.qu_list.append(n) def count (self): return len (self.qu_list) def last (self): return self.qu_list[len(self.qu_list)-1] }}} {{{~cpp ---------------------------------------------------------------------- Ran 2 tests in 0.000s OK }}} dequeue를 만들어보자. dequeue 인 경우 두가지를 생각해볼 수 있겠다. 하나는 최초의 값이 제대로 리턴이 되는 것과, queue안에 저장된 갯수가 줄어든다는 점이다. {{{~cpp import unittest from queue import Queue class QueueTestCase (unittest.TestCase): def testEnqueue (self): q = Queue () q.enqueue (10) self.assertEquals (q.last(), 10) q.enqueue (20) self.assertEquals (q.last(), 20) def testCount (self): q = Queue () q.enqueue (10) self.assertEquals (q.count(), 1) q.enqueue (20) self.assertEquals (q.count(), 2) q.enqueue (30) self.assertEquals (q.count(), 3) def testDequeueData (self): q = Queue () q.enqueue (1) q.enqueue (2) q.enqueue (3) self.assertEquals (q.dequeue(),1) self.assertEquals (q.dequeue(),2) self.assertEquals (q.dequeue(),3) suite = unittest.makeSuite (QueueTestCase, "test") runner = unittest.TextTestRunner () runner.run (suite) }}} {{{~cpp ====================================================================== ERROR: testDequeueData (TestCaseQueue.QueueTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\USER\reset\TestCaseQueue.py", line 26, in testDequeueData AttributeError: Queue instance has no attribute 'dequeue' ---------------------------------------------------------------------- Ran 3 tests in 0.050s FAILED (errors=1) }}} dequeue 메소드가 없다고 나온다. 요구하는데로 채워주자. {{{~cpp class Queue: def __init__ (self): self.qu_list = [] def enqueue (self, n): self.qu_list.append(n) def count (self): return len (self.qu_list) def last (self): return self.qu_list[len(self.qu_list)-1] def dequeue (self): return 0 }}} {{{~cpp ====================================================================== FAIL: testDequeueData (TestCaseQueue.QueueTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\USER\reset\TestCaseQueue.py", line 26, in testDequeueData File "C:\PYTHON22\lib\unittest.py", line 286, in failUnlessEqual raise self.failureException, \ AssertionError: 0 != 1 ---------------------------------------------------------------------- Ran 3 tests in 0.000s FAILED (failures=1) }}} 자.. dequeue를 구현하자. {{{~cpp class Queue: def __init__ (self): self.qu_list = [] def enqueue (self, n): self.qu_list.append(n) def count (self): return len (self.qu_list) def last (self): return self.qu_list[len(self.qu_list)-1] def dequeue (self): return self.qu_list.pop(0) }}} {{{~cpp ---------------------------------------------------------------------- Ran 3 tests in 0.000s OK }}} 이쯤 되면 매번 TestCase 작성할 때마다 Queue 인스턴스를 만든다. 이것은 중복되는 일이다. 다음과 같이 setUp 메소드를 구현해주자. 기존에 q를 self.q로 바꾸는것은 replace를 사용하면 쉽다. {{{~cpp import unittest from queue import Queue class QueueTestCase (unittest.TestCase): def setUp (self): self.q = Queue () def testEnqueue (self): self.q = Queue () self.q.enqueue (10) self.assertEquals (self.q.last(), 10) self.q.enqueue (20) self.assertEquals (self.q.last(), 20) def testCount (self): self.q.enqueue (10) self.assertEquals (self.q.count(), 1) self.q.enqueue (20) self.assertEquals (self.q.count(), 2) self.q.enqueue (30) self.assertEquals (self.q.count(), 3) def testDequeueData (self): self.q.enqueue (1) self.q.enqueue (2) self.q.enqueue (3) self.assertEquals (self.q.dequeue(),1) self.assertEquals (self.q.dequeue(),2) self.assertEquals (self.q.dequeue(),3) suite = unittest.makeSuite (QueueTestCase, "test") runner = unittest.TextTestRunner () runner.run (suite) }}} 마지막 한가지. dequeue 를 구현할때 예상했던 일중 하나인 갯수를 세어보자. {{{~cpp import unittest from queue import Queue class QueueTestCase (unittest.TestCase): def setUp (self): self.q = Queue () def testEnqueue (self): self.q = Queue () self.q.enqueue (10) self.assertEquals (self.q.last(), 10) self.q.enqueue (20) self.assertEquals (self.q.last(), 20) def testCount (self): self.q.enqueue (10) self.assertEquals (self.q.count(), 1) self.q.enqueue (20) self.assertEquals (self.q.count(), 2) self.q.enqueue (30) self.assertEquals (self.q.count(), 3) def testDequeueData (self): self.q.enqueue (1) self.q.enqueue (2) self.q.enqueue (3) self.assertEquals (self.q.dequeue(),1) self.assertEquals (self.q.dequeue(),2) self.assertEquals (self.q.dequeue(),3) def testDequeueCount (self): self.q.enqueue (1) self.q.enqueue (2) self.q.enqueue (3) self.q.dequeue () self.assertEquals (self.q.count(),2) self.q.dequeue () self.assertEquals (self.q.count(),1) self.q.dequeue () self.assertEquals (self.q.count(),0) suite = unittest.makeSuite (QueueTestCase, "test") runner = unittest.TextTestRunner () runner.run (suite) }}} {{{~cpp ---------------------------------------------------------------------- Ran 4 tests in 0.050s OK }}} 완성코드.. TestCaseQueue.py {{{~cpp import unittest from queue import Queue class QueueTestCase (unittest.TestCase): def setUp (self): self.q = Queue () def testEnqueue (self): self.q = Queue () self.q.enqueue (10) self.assertEquals (self.q.last(), 10) self.q.enqueue (20) self.assertEquals (self.q.last(), 20) def testCount (self): self.q.enqueue (10) self.assertEquals (self.q.count(), 1) self.q.enqueue (20) self.assertEquals (self.q.count(), 2) self.q.enqueue (30) self.assertEquals (self.q.count(), 3) def testDequeueData (self): self.q.enqueue (1) self.q.enqueue (2) self.q.enqueue (3) self.assertEquals (self.q.dequeue(),1) self.assertEquals (self.q.dequeue(),2) self.assertEquals (self.q.dequeue(),3) def testDequeueCount (self): self.q.enqueue (1) self.q.enqueue (2) self.q.enqueue (3) self.q.dequeue () self.assertEquals (self.q.count(),2) self.q.dequeue () self.assertEquals (self.q.count(),1) self.q.dequeue () self.assertEquals (self.q.count(),0) suite = unittest.makeSuite (QueueTestCase, "test") runner = unittest.TextTestRunner () runner.run (suite) }}} Queue.py {{{~cpp class Queue: def __init__ (self): self.qu_list = [] def enqueue (self, n): self.qu_list.append(n) def count (self): return len (self.qu_list) def last (self): return self.qu_list[len(self.qu_list)-1] def dequeue (self): return self.qu_list.pop(0) }}} Python Shell 에서 써먹어보자. {{{~cpp >>> import queue >>> q = queue.Queue () >>> q.enqueue (10) >>> q.enqueue (20) >>> q.enqueue (30) >>> q.dequeue () 10 >>> q.dequeue () 20 >>> q.dequeue () 30 >>> }}} === TestCode 먼저 만들기 & 코드 키워나가기 === TestFirstProgramming의 핵심은 테스트프로그램을 먼저 작성함으로서 '무엇을 해야 할것인가' 에 대한 촛점을 분명이 한다는 점에 있다. 일단 테스트를 만들고 모듈은 비워둔다. 테스트를 함으로서 에러가 난다. 즉, 인터프리터 또는 컴파일러가 모듈을 요구한다. 모듈을 채운다. 테스트가 failure가 난다. 모듈의 알고리즘이 제대로 되지 않았다는 뜻이다. 테스트를 통과할때까지 프로그래밍 한다. 단, 테스트코드도 처음부터 완벽하게 모든 경우를 생각할 순 없다. 생각할 수 있는 가장 단순한 것부터 한가지씩 생각해 나간다. 복잡하면 나눈다. Divide & Conquer 한다. ---- ["TestFirstProgramming"]