유닛 테스트란?! (with Python)

http://tech.tokopedia.com/assets/img/u/cover--unit_test.jpg

유닛테스트


(위키백과에 의하면)

 컴퓨터 프로그래밍에서 소스 코드의 특정 모듈이 의도된 대로 정확히 작동하는지 검증하는 절차다.
 즉, 모든 함수와 메소드에 대한 테스트 케이스(Test case)를 작성하는 절차를 말한다. 

 이를 통해서 언제라도 코드 변경으로 인해 문제가 발생할 경우, 단시간 내에 이를 파악하고 바로 잡을 수 있도록 해준다.




보니까, 한마디로

'완벽을 만드는 과정'

인 것 같다.

시간이 걸리고, 노력이 더 들어가더라도!
더욱 완성도있는 프로그램을 만들 수 있도록 도와줄 것이다.







'Unit Test' with Python



먼저, 아래의 코드를 작성했다.


# Calc.py
def add(a, b):
    return a + b
def sub(a, b):
    return a - b


위 함수들을 테스트해보고 싶다고 하면,



# test_Calc.py
import unittest # unittest 모듈은 자동 설치 (파이썬 라이브러리)
import Calc
class Test_Calc(unittest.TestCase):
    def test_add(self):
        c = Calc.add(30, 20)
        self.assertEqual(c, 50, "Failed1") # c와 50 비교. 실패시 "Failed1".
    def test_sub(self):
        c = Calc.sub(30, 20, "Failed2")
        self.assertEqual(c, 10)
if __name__ == '__main__':
    unittest.main()


이렇게 작성할 수 있겠다.


Test_Calc라는 클래스를 만드는데, unittest.TestCase라는 클래스를 상속받았다.

그 안에는 test_add, test_sub 라는 테스트 메소드를 작성하였고,
각 메소드에는 assertEqual 함수를 사용해 add/sub함수의 결과값(c)이 두 번째 인자와 같은지 비교하고 있다. (실패 시, 세 번째 인자의 문자열 실행)

마지막으로 unittest.main()이 실행되면 유닛테스트가 실행되고, 프로그램이 종료되게 된다.



TestCase 클래스의 Assert Functions ↓ ↓ 
MethodChecks thatNew in
assertEqual(a, b)a == b
assertNotEqual(a, b)a != b
assertTrue(x)bool(x) is True
assertFalse(x)bool(x) is False
assertIs(a, b)a is b3.1
assertIsNot(a, b)a is not b3.1
assertIsNone(x)x is None3.1
assertIsNotNone(x)x is not None3.1
assertIn(a, b)a in b3.1
assertNotIn(a, b)a not in b3.1
assertIsInstance(a, b)isinstance(a, b)3.2
assertNotIsInstance(a, b)not isinstance(a, b)3.2





Test Fixture


그리고 테스트 전과 후에 필요한 행동이 있다면, 
TestCase 클래스의 setUp() tearDown()Functions를 활용할 수도 있다.

이 기능을 Test Fixture라고 하며.
setUp()은 유닛 테스트 실행 시, '준비 작업'을 위해 실행되는 메소드이고,
tearDown()은 유닛 테스트가 종료되기 직전에, '마무리' 혹은 '사후 처리'를 위해 실행되는 메소드이다.

들어보면 마치, 클래스의 '생성자'와 '소멸자' 같다.

사실 '생성자'와 '소멸자'와 똑같은 역할을 한다.


# Util.py
import os
def file_len(filename):
    f = open(filename, "r")
    f.seek(0, os.SEEK_END)
    return f.tell()
def char_count(filename, char_to_find):
    count = 0
    f = open(filename, "r")
    for word in f:
        for char in word:
            if char == char_to_find:
                count += 1
    return count


먼저, 
file_len함수는 '파일 내용의 길이'를 알려주고,
char_count함수는 두 번째 인자로 준 '문자'의 수를 카운트한다.


이를 테스트하기 위해,

# test_Util.py
import unittest
import os
import Util
class Test_Util(unittest.TestCase):
    testfile = 'test.txt' # 생성하고자 하는 파일 이름
    # Fixture
    def setUp(self):
        f = open(Test_Util.testfile, 'w') # 파일 생성
        f.write('Blogger') # 파일 내용 씀
        f.close()
    def tearDown(self):
        try:
            os.remove(Test_Util.testfile) # 파일 삭제
        except:
            pass
    def test_file_len(self):
        leng = Util.file_len(Test_Util.testfile)
        self.assertEqual(leng, 7)
    def test_char_count(self):
        cnt = Util.char_count(Test_Util.testfile, 'g')
        self.assertEqual(cnt, 2)
if __name__ == '__main__':
    unittest.main()


이러한 코드를 작성한다.

tset_~~~는 테스트 메소드이고, setUp/tearDown메소드만 눈여겨보면 된다.

파일입출력이 필요한 Util.py의 메소드를 테스트하려면,
직접 파일을 만들어보며 테스트해보아야 한다.

그러므로, TestCase클래스의 상속을 받는 Test_Util클래스에게
직접 파일을 만들어볼 수 있게 해주어야하는데,

setUp()메소드가 필요할 차례다.
메소드 안에 테스트용 파일을 생성하게 작성해주고,

tearDown()메소드에는
테스트용 파일을 삭제하게 하면 된다.(os.remove)





아직 학생으로서, 유닛 테스트의 큰 메리트는 못 느끼겠다.

그러나 나중에 취업하고는?

유용히 사용될 수도 있을 거라 생각한다!

댓글