U E D R , A S I H C RSS

TFP예제/Queue

1. Example - Test First Programming 으로 만들어보는 Queue

솔직히 Python도 처음이고 TFP 도 처음이여서 제대로 했다는 보장이 안된다. --; (특히, count 메소드를 먼저 잡았다는 점에서 두가지 Test Case를 만들었다는 점이 맘에 안든다. 추후에 다른 더 좋은 예제가 생기면 그때 바꿔버리던지 해야지. -_;

1.1. 준비. Queue를 만들거다.

TestCaseQueue.py
~cpp 
import unittest

suite = unittest.makeSuite (QueueTestCase, "test")

runner = unittest.TextTestRunner ()
runner.run (suite)

Queue.py
~cpp 
(없음)

1.2. Queue다. 무엇을 하는 넘일까?

무엇을 해야 할까... 일단 이녀석은 값을 enqueue하면 하나씩 저장될 것이다. 그러면 저장되는 갯수가 늘어날 것이다.

1.3. 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
>>> 

1.4. TestCode 먼저 만들기 & 코드 키워나가기

TestFirstProgramming의 핵심은 테스트프로그램을 먼저 작성함으로서 '무엇을 해야 할것인가' 에 대한 촛점을 분명이 한다는 점에 있다. 일단 테스트를 만들고 모듈은 비워둔다. 테스트를 함으로서 에러가 난다. 즉, 인터프리터 또는 컴파일러가 모듈을 요구한다. 모듈을 채운다. 테스트가 failure가 난다. 모듈의 알고리즘이 제대로 되지 않았다는 뜻이다. 테스트를 통과할때까지 프로그래밍 한다.

단, 테스트코드도 처음부터 완벽하게 모든 경우를 생각할 순 없다. 생각할 수 있는 가장 단순한 것부터 한가지씩 생각해 나간다. 복잡하면 나눈다. Divide & Conquer 한다.


Valid XHTML 1.0! Valid CSS! powered by MoniWiki
last modified 2009-05-27 07:09:19
Processing time 0.0887 sec