본문 바로가기
프로그래밍/Python

[TDD][Python] unittest - 예제로 익혀보기(3)

by 우주를놀라게하자 2022. 3. 16.
반응형
SMALL

이번엔 지난번 글에 이어서 추가로 unittest를 디버깅하는 방법에 대해서 알아보자

앞선 방법으로 테스트를 구현하는 방법은 알게되었는데, 여기서 생기는 의문점은 바로 기존에 pirnt를 사용한 디버깅이 되지 않는다는 점이다. 이를 해결하기 위해 이번에는 unittest의 간단한 명령어들과 추가적으로 asstert의 다른 함수들을 정리해 둘 생각이다. 추가적인 코드는 길지 않으므로 바로 코드로 넘어가보자

📃 소스코드 및 설명(test_datetimehelper.py)

"""
datetimehelper 모듈 테스터
"""
import datetime
import unittest
from unittest.mock import patch
import datetimehelper
class DateTimeHelperTestCase(unittest.TestCase):
    """
    Unit Test - testcase class [DateTimeHelper 클래스]
    """

    # 전역 변수 선언 => tearDown() 디버깅 용
    response = ""

    # 매 테스트 메소드 실행 전 동작 __init__과 같은 역할을 한다고 볼 수 있다.
    def setUp(self) -> None:
        self.obj = datetimehelper.DateTimeHelper()

    
    def test_us_korea_conversion(self):
        """
        미국식 날짜 -> 한국식 날짜 변경 테스트
        """
        # 테스트 케이스 생성
        d1 = '08/12/2016'
        d2 = '24/11/2021'
        d3 = '02/02/2019'
        d4 = '16/03/2021'

        self.response = self.obj.us_to_korea(d1)
        
        self.assertEqual(self.obj.us_to_korea(d1), '2016/12/08')
        self.assertEqual(self.obj.us_to_korea(d2), '2021/11/24')
        self.assertEqual(self.obj.us_to_korea(d3), '2019/02/02')
        self.assertEqual(self.obj.us_to_korea(d4), '2021/03/16')
    
    def test_date(self):
        """
        datetimehelper.py > today() 메소드 테스트
        """

        # 테스트를 위한 날짜를 지정해서 만들어줍니다.
        test_date = datetime.datetime(year=2022,month=2,day=10)

        # patch를 통해 today() 메소드에 내가 지정한 날짜를 넣고 테스를 진행합니다.
        #                   객체, 객채의 메소드 명,   테스트용 데이터 
        with patch.object(self.obj, 'today', return_value=test_date):
            self.response = self.obj.date()
            self.assertEqual(self.response, '10/02/2022')
    
    def test_weekday(self):
        """
        datetimehelper.py > weekday() 메소드 테스트
        """

        # 테스트를 위한 날짜를 지정해서 만들어줍니다.
        test_date = datetime.datetime(year=2022,month=2,day=10)

        # self.obj = datetimehelper.DateTimeHelper()에 있는 today메소드에 테스트를 원하는 데이터를 넣고 테스트를 진행합니다.
        with patch.object(self.obj, 'today', return_value=test_date):
            self.response = self.obj.weekday()
            self.assertEqual(self.response, 'Thursday')

    # 매 테스트 메소드 실행 후 동작 디버깅
    def tearDown(self) -> None:
        print('결과 : ' + self.response)
    
if __name__ == '__main__':
    unittest.main()

 

추가된 코드는 맨아래 tearDown() 메소드와 여기서 프린트를 해주는 response의 전역변수 설정과 각 메소드에서 전역변수 response의 활용이다.

그럼 여기서 2가지를 알아보자

  • setUp() - TestCase클래스의 매 테스트 메소드가 실행하기 전 동작
  • tearDown() - 매 테스트 메소드가 실행 후 동작

위의 방식으로 이제 print를 활용하여 디버깅을 활용할 수 있게되었다. 결과는 아래와 같다.

 

위와 같이 내가 출력하고자 하는 결과들을 확인 할 수 있다. 더 나아가 더 상세한 출력을 줄 수 있는 옵션들도 있다.

실행 명령어

python -m unittest discover [option]
1. -v : 상세 결과
2. -f : 첫 번째 실패 또는 오류시 중단
3. -s : 시작할 디렉토리
4. -p : 테스트 파일과 일치하는 패턴
5. -t : 프로젝트의 최상위 디렉토리

나는 여기서 1번 옵션을 사용해서 출력을 진행해보았다. 아래의 결과처럼 더 디테일한 결과를 출력한다. 출력되는 메소드명, 어떤 클래스인지 그리고 맨 마지막 tearDown()까지 출력이 된다. 

 

ETC

TestCase.assert 메소드
1) assertEqual(A, B, Msg) - A, B가 같은지 테스트
2) assertNotEqual(A, B, Msg) - A, B가 다른지 테스트
3) assertTrue(A, Msg) - A가 True인지 테스트
4) assertFalse(A, Msg) - A가 False인지 테스트
5) assertIs(A, B, Msg) - A, B가 동일한 객체인지 테스트
6) assertIsNot(A, B, Msg) - A, B가 동일하지 않는 객체인지 테스트
7) assertIsNone(A, Msg) - A가 None인지 테스트
8) assertIsNotNone(A, Msg) - A가 Not None인지 테스트
9) assertRaises(ZeroDivisionError, myCalc.add, 4, 0) - 특정 에러 확인

 

결론

TDD 장점
소스코드의 품질이 높다.
재설계 및 디버깅 시간이 절감된다.

TDD 단점
단기적 코드일 경우 생산성이 떨어진다.
실제 코드보다 테스트 케이스가 더 커질 수 있다.

파이썬에서 TDD가 필요한 이유
1) 파이썬에는 정적 타입 검사 기능이 없다. (Python 3.6 에서는 정적 타입 선언 가능)
2) 동적언어이기 때문에 TDD를 하기에 적합하다.
3) 파이썬은 간결성과 단순함으로 생산성이 높은 반면 런타임 오류가 발생할 수도 있다.
4) 파이썬을 신뢰할 수 있는 유일한 방법은 테스트를 하는 것이다.

반응형
LIST