단위 테스트의 중요성
그 동안 프로그래머(?)아니 코더로 3년 정도 일을 하면서 단위 테스트에 대해서는 거의 신경을 쓰지 않았던 것 같다. 왜냐하면 첫째로는 아무도 나에게 단위테스트를 알려준 사람이 없고 둘째로는 이것이 중요하다고 말한 사람이 없으며 마지막으로 나도 이것이 왜 중요한지 몰랐기 때문이다.
그러다가 조금씩 단위테스트를 알아갈 때 나는 이것이 단순히 단위테스트를 자동화는 툴인줄 알았었다. 이것이 전적으로 틀린 말이 아니지만 정확하지도 않은 것 같다 지금 생각해보면
단위테스트를 기반으로한 개발(TDD)가 왜 설계 방법인지를 이제야서야 조금씩 알아가고 있는 것 같다. 왜 아무도 나에게 이런 이야기를 하지 않았는지 모르겠습니다. ㅠㅠㅠ
아마도 그것은 한국의 개발 문화 때문인 것도 같습니다. 교육을 가더라도 단위테스트는 그냥 Skip해버립니다. 그러면서 대부분하는 말은 이것을 실체로는 사용하지 않아요 입니다.
현업에서도 개발 기간에 맞추어 빠르게 개발을 하다보니 단위테스트를 작성하지 않거나 아니면 return true로 만들어 버립니다.
단위 테스트의 중요성
그 동안 프로그래머(?)아니 코더로 3년 정도 일을 하면서 단위 테스트에 대해서는 거의 신경을 쓰지 않았던 것 같다. 왜냐하면 첫째로는 아무도 나에게 단위테스트를 알려준 사람이 없고 둘째로는 이것이 중요하다고 말한 사람이 없으며 마지막으로 나도 이것이 왜 중요한지 몰랐기 때문이다.
그러다가 조금씩 단위테스트를 알아갈 때 나는 이것이 단순히 단위테스트를 자동화는 툴인줄 알았었다. 이것이 전적으로 틀린 말이 아니지만 정확하지도 않은 것 같다 지금 생각해보면
단위테스트를 기반으로한 개발(TDD)가 왜 설계 방법인지를 이제야서야 조금씩 알아가고 있는 것 같다. 왜 아무도 나에게 이런 이야기를 하지 않았는지 모르겠습니다. ㅠㅠㅠ
아마도 그것은 한국의 개발 문화 때문인 것도 같습니다. 교육을 가더라도 단위테스트는 그냥 Skip해버립니다. 그러면서 대부분하는 말은 이것을 실체로는 사용하지 않아요 입니다.
현업에서도 개발 기간에 맞추어 빠르게 개발을 하다보니 단위테스트를 작성하지 않거나 아니면 return true로 만들어 버립니다.
하지만 이제부터는 그러지 않기를 바라면서 이 정리를 시작해 봅니다. 일단은 단위테스트가 어떠한 것인지 알아야 하기에 단위테스트에 대해서 알아봅니다.
본 글은 https://www.tutorialspoint.com/unittest_framework/unittest_framework_overview.htm 을 참고로 작성하였습니다.
단위테스트란?
‘unittest’는 테스트 자동화, 테스트를 위한 설정 및 종료 코드 공유, 컬렉션으로 테스트 집계, 리포팅 프레임워크에서 테스트의 독립을 지원합니다.
unittest 모듈은 일련의 테스트에 대해 이러한 특성을 쉽게 지원할 수 있는 클래스를 제공합니다.
이를 달성하기 위해 unittest는 다음과 같은 중요한 개념을 지원합니다.
테스트 픽스쳐(test fixture) - 하나 이상의 테스트를 수행하는 데 필요한 준비 작업과 연관 클린업 작업을 나타냅니다. 예를 들어, 임시 또는 프록시 데이터베이스, 디렉토리 작성 또는 서버 프로세스 시작과 관련될 수 있습니다.
테스트 케이스 - 이것은 테스트의 최소 단위입니다. 특정 입력 세트에 대한 특정 응답을 확인합니다. unittest는 새로운 테스트 케이스를 작성하는 데 사용할 수 있는 기본클레스인 TestCase를 제공합니다.
테스트 슈트 - 이것은 테스트 케이서, 테스트 스위트 또는 둘 모두의 집합니다. 이것은 함께 실행되어야하는 테스트를 집계하는 데 사용됩니다. 테스트 스위트는 TestSuite 클래스에 의해 구현됩니다.
테스트 Runner - 테스트 실행을 조정하고 결과를 사용자에게 제공하는 구성 요소입니다. 러너는 그래픽 인터페이스나 텍스트 인터페이스를 사용하거나 특수 값을 반환하여 테스트 실행 결과를 나타낼 수 있습니다.
단위 테스트 만들어 보기
- 프로그램에서 unittest 모듈을 가져옵니다.
- 테스트할 함수를 정의하십시오. 다음 예제에서 add() 함수는 테스트를 거친다.
- unittest.TestCase를 하위 클래스화하여 테스트 사례를 만듭니다.
- 테스트를 클래스 내부의 메소드로 정의합니다. 메소드 이름은 ‘test’로 시작해야 합니다.
- 각 테스트는 TestCase 클래스의 assert 함수를 호출합니다. 다양한 유형의 assert가 있습니다. 다음 예제에서는 assertEquals() 함수를 호출합니다.
- assertEquals() 함수는 add() 함수의 결과를 arg2 인수와 비교하고 비교가 실패하면 assertionError를 발생시킵니다.
- 마지막으로 unittest 모듈에서 main() 메서드를 호출합니다.
import unittest
def add(x,y):
return x + y
class SimpleTest(unittest.TestCase):
def testadd1(self):
self.assertEquals(add(4,5),9)
if __name__ == '__main__':
unittest.main()
- script를 command line로 실행합니다.
python SimpleTest.py
-----------------------------------------
Ran 1 test in 0.000s
OK
테스트 클래스 지원 메소드
- setUp()
테스트 fixture를 준비하기 위해 호출된 메소드. 이것은 테스트 메소드를 호출하기 직전에 호출됩니다. - tearDown()
테스트 메소드가 호출되고 결과가 기록된 직후에 호출될 메소드. 이것은 테스트 메소드가 예외를 발생시키는 경우에도 호출됩니다. - setUpClass()
개발 클래스에서 테스트하기 전에 호출될 클래스 메소드입니다. - tearDownClass()
개별 클래스의 테스트가 실행된 이후에 실행될 메소드입니다. - run(result=None)
결과를 결과로 전달 된 테스트 결과 개체로 결과를 수집하여 테스트를 실행합니다. - skipTest(reason)
테스트 메소드에서 이것을 호출하거나 현재 테스트를 건너 뜁니다. - debug()
결과를 수집하지 않고 테스트를 실행하십시오. - shortDescription()
테스트에 대한 한 줄짜리 설명을 반환합니다.
import unittest
class simpleTest2(unittest.TestCase):
def setUp(self):
self.a = 10
self.b = 20
name = self.shortDescription()
if name == "Add":
self.a = 10
self.b = 20
print name, self.a, self.b
if name == "sub":
self.a = 50
self.b = 60
print name, self.a, self.b
def tearDown(self):
print '\nend of test',self.shortDescription()
def testadd(self):
"""Add"""
result = self.a+self.b
self.assertTrue(result == 100)
def testsub(self):
"""sub"""
result = self.a-self.b
self.assertTrue(result == -10)
if __name__ == '__main__':
unittest.main()
- 결과
C:\Python27>python test2.py
Add 10 20
F
end of test Add
sub 50 60
end of test sub
.
================================================================
FAIL: testadd (__main__.simpleTest2)
Add
----------------------------------------------------------------------
Traceback (most recent call last):
File "test2.py", line 21, in testadd
self.assertTrue(result == 100)
AssertionError: False is not true
----------------------------------------------------------------------
Ran 2 tests in 0.015s
FAILED (failures = 1)
Class Fixture
TestCase 클래스에는 TestCase 클래스내에서 개별 테스트를 실행하기 전에 실행할 수 있는 setUpClass() 메소드가 있습니다. 마찬가지고, tearDownClass() 메소드는 클래스의 모든 테스트 후에 실행됩니다. 두 메소드는 모두 클래스 메소드립니다. 따라서 @classmethod를 Annotation해야 합니다.
import unittest
class TestFixtures(unittest.TestCase):
@classmethod
def setUpClass(cls):
print 'called once before any tests in class'
@classmethod
def tearDownClass(cls):
print '\ncalled once after all tests in class'
def setUp(self):
self.a = 10
self.b = 20
name = self.shortDescription()
print '\n',name
def tearDown(self):
print '\nend of test',self.shortDescription()
def test1(self):
"""One"""
result = self.a+self.b
self.assertTrue(True)
def test2(self):
"""Two"""
result = self.a-self.b
self.assertTrue(False)
if __name__ == '__main__':
unittest.main()
TestSuite Class
파이썬의 테스트 프레임워크는 테스트하는 기능에 따라 그룹화 될 수 있는 유용한 기능을 제공한다. 이 기능은 unittest 모듈의 TestSuite 클래스에서 사용할 수 있습니다. 다음 단계는 테스트 스위트를 작성하고 실행하는 단계입니다.
다음 단계는 TestSuite를 작성하고 실행하는 단계입니다.
- TestSuite 클래스 생성
suite = unittest.TestSuite
- suite에 있는 TestCase안에 테스트를 추가한다.
suite.addTest(testcase class)
- makeSuite() 메서드를 사용하여 클래스의 테스트를 추가 할 수도 있습니다.
suite = unittest.makeSuite(test case class)
- 각각의 테스트는 또한 suite안에 추가될 수 있습니다.
suite.addTest(testcaseclass("testmethod"))
- TestTestRunner 클래스의 객체를 만든다.
runner = unittest.TextTestRunner()
- run() 메서드를 호출하여 suite의 모든 테스트를 실행할 수 있다.
runner.run(suite)
TestSuite 클래스의 메소드들이다.
- addTest() - Test suite안에 테스트를 추가한다.
- addTests() - 여러 TestCase Class들에 테스트들을 추가한다.
- run() - 테스트를 수행하고 테스트의 결과를 출력해 준다.
- debug() - 결과수집 없이 테스트를 수행한다.
- countTestCases() - 테스트 객체로부터 테스트의 숫자를 리턴한다.
import unittest
class suiteTest(unittest.TestCase):
def setUp(self):
self.a = 10
self.b = 20
def testadd(self):
"""Add"""
result = self.a+self.b
self.assertTrue(result == 100)
def testsub(self):
"""sub"""
result = self.a-self.b
self.assertTrue(result == -10)
def suite():
suite = unittest.TestSuite()
## suite.addTest (simpleTest3("testadd"))
## suite.addTest (simpleTest3("testsub"))
suite.addTest(unittest.makeSuite(simpleTest3))
return suite
if __name__ == '__main__':
runner = unittest.TextTestRunner()
test_suite = suite()
runner.run (test_suite)
TestLoader Class
unittest 패키지에는 클래스와 모듈에서 테스트 스위트를 만드는 데 사용되는 TestLoader 클래스가 있습니다. 기본적으로 unittest.main (0 메서드가 호출되면 unittest.defaultTestLoader 인스턴스가 자동으로 만들어 지지만 명시 적 인스턴스에서는 특정 속성을 사용자 지정할 수 있습니다.
다음 코드에서 두 클래스의 테스트는 TestLoader 객체를 사용하여 List에 수집됩니다.
import unittest
testList = [Test1, Test2]
testLoad = unittest.TestLoader()
TestList = []
for testCase in testList:
testSuite = testLoad.loadTestsFromTestCase(testCase)
TestList.append(testSuite)
newSuite = unittest.TestSuite(TestList)
runner = unittest.TextTestRunner()
runner.run(newSuite)
아래는 TestLoader Class의 메소들이다.
- loadTestsFromTestCase()
- loadTestsFromModule()
- loadTestsFromName()
- discover()
TestResult Class
- Errors
- Failures
- Skipped
- wasSuccessful()
- stop()
- startTestRun()
- stopTestRun()
- testsRun
- Buffer
if __name__ == '__main__':
runner = unittest.TextTestRunner()
test_suite = suite()
result = runner.run (test_suite)
print "---- START OF TEST RESULTS"
print result
print "result::errors"
print result.errors
print "result::failures"
print result.failures
print "result::skipped"
print result.skipped
print "result::successful"
print result.wasSuccessful()
print "result::test-run"
print result.testsRun
print "---- END OF TEST RESULTS"
---- START OF TEST RESULTS
<unittest.runner.TextTestResult run = 2 errors = 0 failures = 1>
result::errors
[]
result::failures
[(<__main__.suiteTest testMethod = testadd>, 'Traceback (most recent call last):\n
File "test3.py", line 10, in testadd\n
self.assertTrue(result == 100)\nAssert
ionError: False is not true\n')]
result::skipped
[]
result::successful
False
result::test-run
2
---- END OF TEST RESULTS
Assert
Python 테스팅 프레임 워크는 특정 조건을 테스트하는 파이썬의 기본 제공 assert () 함수를 사용합니다. Assert이 실패하면 AssertionError가 발생합니다. 테스트 프레임워크는 테스트를 실패로 식별합니다. 다른 예외는 오류로 처리됩니다.
Unittest 모듈에는 다음 세 새의 assert 메소드가 있다.
- Basic Boolean Asserts
- Comparative Asserts
- Asserts for Collections
기본 Assert기능은 연산 결과가 참인지 거짓인지를 평가합니다. 모든 assert 메소드는 지정된 경우, 실패시 오류 메시지로 사용되는 msg 인수를 승인합니다.
- assertEqual(arg1, arg2, msg = None)
- assertNotEqual(arg1, arg2, msg = None)
- assertTrue(expr, msg = None)
- assertFalse(expr, msg = None)
- assertIs(arg1, arg2, msg = None)
- assertIsNot(arg1, arg2, msg = None)
- assertIsNone(expr, msg = None)
- assertIn(arg1, arg2, msg = None)
- assertNotIn(arg1, arg2, msg = None)
- assertIsInstance(obj, cls, msg = None)
- assertNotIsInstance(obj, cls, msg=None)
아래는 위의 assertion 함수를 구현하는 코드이다.
import unittest
class SimpleTest(unittest.TestCase):
def test1(self):
self.assertEqual(4 + 5,9)
def test2(self):
self.assertNotEqual(5 * 2,10)
def test3(self):
self.assertTrue(4 + 5 == 9,"The result is False")
def test4(self):
self.assertTrue(4 + 5 == 10,"assertion fails")
def test5(self):
self.assertIn(3,[1,2,3])
def test6(self):
self.assertNotIn(3, range(5))
if __name__ == '__main__':
unittest.main()
FAIL: test2 (__main__.SimpleTest)
----------------------------------------------------------------------
Traceback (most recent call last):
File "C:\Python27\SimpleTest.py", line 9, in test2
self.assertNotEqual(5*2,10)
AssertionError: 10 == 10
FAIL: test4 (__main__.SimpleTest)
----------------------------------------------------------------------
Traceback (most recent call last):
File "C:\Python27\SimpleTest.py", line 13, in test4
self.assertTrue(4+5==10,"assertion fails")
AssertionError: assertion fails
FAIL: test6 (__main__.SimpleTest)
----------------------------------------------------------------------
Traceback (most recent call last):
File "C:\Python27\SimpleTest.py", line 17, in test6
self.assertNotIn(3, range(5))
AssertionError: 3 unexpectedly found in [0, 1, 2, 3, 4]
----------------------------------------------------------------------
Ran 6 tests in 0.001s
FAILED (failures = 3)
두 번째 비교 assert입니다.
- assertAlmostEqual (first, second, places = 7, msg = None, delta = None)
- assertNotAlmostEqual (first, second, places, msg, delta)
- assertGreater (first, second, msg = None)
- assertGreaterEqual (first, second, msg = None)
- assertLess (first, second, msg = None)
- assertLessEqual (first, second, msg = None)
- assertRegexpMatches (text, regexp, msg = None)
- assertNotRegexpMatches (text, regexp, msg = None)
import unittest
import math
import re
class SimpleTest(unittest.TestCase):
def test1(self):
self.assertAlmostEqual(22.0/7,3.14)
def test2(self):
self.assertNotAlmostEqual(10.0/3,3)
def test3(self):
self.assertGreater(math.pi,3)
def test4(self):
self.assertNotRegexpMatches("Tutorials Point (I) Private Limited","Point")
if __name__ == '__main__':
unittest.main()
위의 메소드를 실행시킨 결과입니다.
=====================================================FAIL: test1 (__main__.SimpleTest)
----------------------------------------------------------------------
Traceback (most recent call last):
File "asserttest.py", line 7, in test1
self.assertAlmostEqual(22.0/7,3.14)
AssertionError: 3.142857142857143 != 3.14 within 7 places
================================================================
FAIL: test4 (__main__.SimpleTest)
----------------------------------------------------------------------
Traceback (most recent call last):
File "asserttest.py", line 13, in test4
self.assertNotRegexpMatches("Tutorials Point (I) Private Limited","Point")
AssertionError: Regexp matched: 'Point' matches 'Point' in 'Tutorials Point (I)
Private Limited'
----------------------------------------------------------------------
Ran 4 tests in 0.001s
FAILED (failures = 2)
Collection를 위한 assert
- assertListEqual (list1, list2, msg = None)
- assertTupleEqual (tuple1, tuple2, msg = None)
- assertSetEqual (set1, set2, msg = None)
- assertDictEqual (expected, actual, msg = None)
위의 메소드를 수행한 예제
import unittest
class SimpleTest(unittest.TestCase):
def test1(self):
self.assertListEqual([2,3,4], [1,2,3,4,5])
def test2(self):
self.assertTupleEqual((1*2,2*2,3*2), (2,4,6))
def test3(self):
self.assertDictEqual({1:11,2:22},{3:33,2:22,1:11})
if __name__ == '__main__':
unittest.main()
위의 메소드를 수행한 결과입니다.
FAIL: test1 (__main__.SimpleTest)
----------------------------------------------------------------------
Traceback (most recent call last):
File "asserttest.py", line 5, in test1
self.assertListEqual([2,3,4], [1,2,3,4,5])
AssertionError: Lists differ: [2, 3, 4] != [1, 2, 3, 4, 5]
First differing element 0:
2
1
Second list contains 2 additional elements.
First extra element 3:
4
- [2, 3, 4]
+ [1, 2, 3, 4, 5]
? +++ +++
FAIL: test3 (__main__.SimpleTest)
----------------------------------------------------------------------
Traceback (most recent call last):
File "asserttest.py", line 9, in test3
self.assertDictEqual({1:11,2:22},{3:33,2:22,1:11})
AssertionError: {1: 11, 2: 22} != {1: 11, 2: 22, 3: 33}
- {1: 11, 2: 22}
+ {1: 11, 2: 22, 3: 33}
? +++++++
----------------------------------------------------------------------
Ran 3 tests in 0.001s
FAILED (failures = 2)
하지만 이제부터는 그러지 않기를 바라면서 이 정리를 시작해 봅니다. 일단은 단위테스트가 어떠한 것인지 알아야 하기에 단위테스트에 대해서 알아봅니다.
본 글은 www.tutorialspoint.com/unittest_framework/unittest_framework.htm 을 참고로 작성하였습니다.
단위테스트란?
‘unittest’는 테스트 자동화, 테스트를 위한 설정 및 종료 코드 공유, 컬렉션으로 테스트 집계, 리포팅 프레임워크에서 테스트의 독립을 지원합니다.
unittest 모듈은 일련의 테스트에 대해 이러한 특성을 쉽게 지원할 수 있는 클래스를 제공합니다.
이를 달성하기 위해 unittest는 다음과 같은 중요한 개념을 지원합니다.
테스트 픽스쳐(test fixture) - 하나 이상의 테스트를 수행하는 데 필요한 준비 작업과 연관 클린업 작업을 나타냅니다. 예를 들어, 임시 또는 프록시 데이터베이스, 디렉토리 작성 또는 서버 프로세스 시작과 관련될 수 있습니다.
테스트 케이스 - 이것은 테스트의 최소 단위입니다. 특정 입력 세트에 대한 특정 응답을 확인합니다. unittest는 새로운 테스트 케이스를 작성하는 데 사용할 수 있는 기본클레스인 TestCase를 제공합니다.
테스트 슈트 - 이것은 테스트 케이서, 테스트 스위트 또는 둘 모두의 집합니다. 이것은 함께 실행되어야하는 테스트를 집계하는 데 사용됩니다. 테스트 스위트는 TestSuite 클래스에 의해 구현됩니다.
테스트 Runner - 테스트 실행을 조정하고 결과를 사용자에게 제공하는 구성 요소입니다. 러너는 그래픽 인터페이스나 텍스트 인터페이스를 사용하거나 특수 값을 반환하여 테스트 실행 결과를 나타낼 수 있습니다.
단위 테스트 만들어 보기
- 프로그램에서 unittest 모듈을 가져옵니다.
- 테스트할 함수를 정의하십시오. 다음 예제에서 add() 함수는 테스트를 거친다.
- unittest.TestCase를 하위 클래스화하여 테스트 사례를 만듭니다.
- 테스트를 클래스 내부의 메소드로 정의합니다. 메소드 이름은 ‘test’로 시작해야 합니다.
- 각 테스트는 TestCase 클래스의 assert 함수를 호출합니다. 다양한 유형의 assert가 있습니다. 다음 예제에서는 assertEquals() 함수를 호출합니다.
- assertEquals() 함수는 add() 함수의 결과를 arg2 인수와 비교하고 비교가 실패하면 assertionError를 발생시킵니다.
- 마지막으로 unittest 모듈에서 main() 메서드를 호출합니다.
import unittest
def add(x,y):
return x + y
class SimpleTest(unittest.TestCase):
def testadd1(self):
self.assertEquals(add(4,5),9)
if __name__ == '__main__':
unittest.main()
- script를 command line로 실행합니다.
python SimpleTest.py
-----------------------------------------
Ran 1 test in 0.000s
OK
테스트 클래스 지원 메소드
- setUp()
테스트 fixture를 준비하기 위해 호출된 메소드. 이것은 테스트 메소드를 호출하기 직전에 호출됩니다. - tearDown()
테스트 메소드가 호출되고 결과가 기록된 직후에 호출될 메소드. 이것은 테스트 메소드가 예외를 발생시키는 경우에도 호출됩니다. - setUpClass()
개발 클래스에서 테스트하기 전에 호출될 클래스 메소드입니다. - tearDownClass()
개별 클래스의 테스트가 실행된 이후에 실행될 메소드입니다. - run(result=None)
결과를 결과로 전달 된 테스트 결과 개체로 결과를 수집하여 테스트를 실행합니다. - skipTest(reason)
테스트 메소드에서 이것을 호출하거나 현재 테스트를 건너 뜁니다. - debug()
결과를 수집하지 않고 테스트를 실행하십시오. - shortDescription()
테스트에 대한 한 줄짜리 설명을 반환합니다.
import unittest
class simpleTest2(unittest.TestCase):
def setUp(self):
self.a = 10
self.b = 20
name = self.shortDescription()
if name == "Add":
self.a = 10
self.b = 20
print name, self.a, self.b
if name == "sub":
self.a = 50
self.b = 60
print name, self.a, self.b
def tearDown(self):
print '\nend of test',self.shortDescription()
def testadd(self):
"""Add"""
result = self.a+self.b
self.assertTrue(result == 100)
def testsub(self):
"""sub"""
result = self.a-self.b
self.assertTrue(result == -10)
if __name__ == '__main__':
unittest.main()
- 결과
C:\Python27>python test2.py
Add 10 20
F
end of test Add
sub 50 60
end of test sub
.
================================================================
FAIL: testadd (__main__.simpleTest2)
Add
----------------------------------------------------------------------
Traceback (most recent call last):
File "test2.py", line 21, in testadd
self.assertTrue(result == 100)
AssertionError: False is not true
----------------------------------------------------------------------
Ran 2 tests in 0.015s
FAILED (failures = 1)
Class Fixture
TestCase 클래스에는 TestCase 클래스내에서 개별 테스트를 실행하기 전에 실행할 수 있는 setUpClass() 메소드가 있습니다. 마찬가지고, tearDownClass() 메소드는 클래스의 모든 테스트 후에 실행됩니다. 두 메소드는 모두 클래스 메소드립니다. 따라서 @classmethod를 Annotation해야 합니다.
import unittest
class TestFixtures(unittest.TestCase):
@classmethod
def setUpClass(cls):
print 'called once before any tests in class'
@classmethod
def tearDownClass(cls):
print '\ncalled once after all tests in class'
def setUp(self):
self.a = 10
self.b = 20
name = self.shortDescription()
print '\n',name
def tearDown(self):
print '\nend of test',self.shortDescription()
def test1(self):
"""One"""
result = self.a+self.b
self.assertTrue(True)
def test2(self):
"""Two"""
result = self.a-self.b
self.assertTrue(False)
if __name__ == '__main__':
unittest.main()
'PYTHON > 강좌' 카테고리의 다른 글
01. Python 프로그램 로깅 (0) | 2012.12.05 |
---|---|
[PATTERN 2] Command 패턴 (0) | 2012.11.19 |
[PATTERN 1] Factory 패턴 예제 (0) | 2012.11.19 |