본문 바로가기

기록지/비트코인 자동 거래 시스템 만들기

[비트코인 자동 거래 시스템] 문제해결 - 복잡한 시스템을 개발할 때 유용한 unittest frame work

반응형

1. 개요

 

 비트코인 자동거래 시스템을 만들던 중 참고했던 책을 보니, 큰 시스템을 만드려면 각 API를 호출하거나 각 기능을 따로 분류하여 모듈 단위로 개발하는 것이 유용하다는 것을 알게 되었다. 전 글을 보면 Korbit API에서 내가 필요한 API의 기능을 각각 실행시키는 모듈을 만드는 것을 알 수 있다.

 

 지금은 Database에 대한 모듈을 작성중인데, CRUD 그리고 연결 부분까지 하면 모듈의 갯수가 꽤나 많아진다는 것이다. 이렇게 되면 많아지는 모듈의 갯수때문에 각각의 모듈을 test하기 힘들게 된다. 지금도 일일이 하나의 Test Class를 만들고 이를 실행하는데 어려움을 겪고 있다. 분명 이러한 문제를 해결할 수 있는 방법이 있을 것이라는 생각을 하고, python에 개발 방법을 찾아보았다. 그러다 알게된 것이 바로 unittest이다. 이제 이 대단한 친구에 대해 설명하겠다.

 

2. unittest

 

 unittest는 Python의 공식 문서를 보며 공부하였다. 다음은 공식 문서의 링크이다.

 

- unittest 공식 문서: https://docs.python.org/ko/3/library/unittest.html

 

unittest — 단위 테스트 프레임워크 — Python 3.10.2 문서

unittest — 단위 테스트 프레임워크 소스 코드: Lib/unittest/__init__.py (당신이 이미 테스트 기본 개념에 친숙하다면, assert 메서드 목록으로 건너뛰어도 좋습니다.) unittest 단위 테스트 프레임워크는

docs.python.org

 

 만약 하나의ㅣ Test Class를 만들고 여기서 다양한 모듈을 시험해본다고 하자, 우리는 다음과 같이 Class를 구현할 수 있다.

 

class TestUnittest():

    def test1(self):
        pass

    def test2(self):
        pass

    ...

 

 우리는 하나의 method를 테스트 하고 싶다면 다음과 같이 실행해야 한다.

 

class TestUnittest():

    def test1(self):
        pass

    def test2(self):
        pass

(TestUnittest()).test1()

 

 지금은 두개여서 괜찮지만, 하나의 Class안에 test method가 20개 생긴다고 생각해보자. 그럼 각각의 method 실행문을 20개를 만들어야 할까? 내가 작성한 Korbit API 모듈 Class는 약 10개의 메소드를 가지고 있다. 나는 이것을 일일이 실행하였지만 절대 사람이 할 행동이 아니다. 한 Class 안에 메소드를 한번에 실행하고 오류를 뱉어줄 수 있는 기능을 바로 unittest가 가지고 있다. 다음 class를 보자.

 

import unittest

class TestUnittest(unittest.TestCase):

    def test_1(self):
        self.string1 = "hello"
        print(self.string1)

    def test_2(self):
        self.string2 = "world"
        print(self.string2)

 

 위에서 본 Class와는 조금 다르다. 각 method가 test_ 로 시작하며, unittest.TestCase Class를 상속받고 있다. 이렇게 Class를 작성한 이유가 있다. 바로 TestUnittest안에 있는 method를 한번에 실행할 수 있기 때문이다. 다음 코드를 보자.

 

import unittest

class TestUnittest(unittest.TestCase):

    def test_1(self):
        self.string1 = "hello"
        print(self.string1)

    def test_2(self):
        self.string2 = "world"
        print(self.string2)

if __name__ == '__main__':
    unittest.main()

 

 이렇게 되면 unittest.main()을 통해 TestUnittest Class의 모든 method들이 실행된다. 만약 각 메소드마다 오류가 하나도 발견되지 않는다면 다음과 같이 출력된다.

 

----------------------------------------------------------------------
Ran 2 tests in 0.042s

OK

 

 만약 오류가 발견된다면 어떻게 될까? 일부로 오류를 가지고 있도록 method를 다음과 같이 수정해주자.

 

import unittest

class TestUnittest(unittest.TestCase):

    def test_1(self):
        self.string1 = "hello"
        print(self.string1)

    def test_2(self):
        self.string2 = "world"
        print(self.string1)

if __name__ == '__main__':
    unittest.main()

 

 해당 코드를 보면 test_2 method에서 존재하지 않는 self.string1을 출력하려한다. 이는 저명한 오류이다. 위의 코드를 실행하게 되면 다음과 같이 출력된다.

 

.E
======================================================================
ERROR: test_2 (__main__.TestUnittest)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "C:/unittest demo.py", line 11, in test_2
    print(self.string1)
AttributeError: 'TestUnittest' object has no attribute 'string1'

----------------------------------------------------------------------
Ran 2 tests in 0.025s

FAILED (errors=1)

 

 출력된 문자열을 보자, 어디서 error가 났는지를 보여준다. 즉, 20개의 모듈이 있더라도 그것을 한번에 실행할 수 있으며 어떤 모듈에서 error가 발생했는지를 알 수 있다는 것이다. 이렇게 Test Module를 구현한다면 아무리 많은 모듈들이 있다 해도 조금 더 빠르게 error를 잡을 수 있을 것이다.

 

3. 결어

 

 초반에 조금 힘들 더라도 개발하는 과정에 있어서 편할 수 있는 방법을 찾고 있다. 단순 문법 공부가 아닌 개발론의 방법이라 조금 어렵지만 발전하는 단계라고 생각한다. 다른 많은 글들을 올렸으면 좋겠다.

반응형