본문 바로가기

Language/Python

Python에서 테스트명을 한글로 표시하는 방법

728x90
반응형

 

개요

Python을 사용할 때 테스트 코드를 작성한다면 주로 unittest 나 pytest를 이용했다. unittest는 코딩테스트나 간단한 코드를 쓰는 상황에서 테스트 케이스를 작성할 때였고 pytest는 백엔드 프레임워크(Django, Flask, FastAPI)를 다룰 때였는데 어떤 걸 사용하더라고 불편한 공통점이 하나 존재했다.

 

그건 테스트 케이스 이름을 한글로 표시하지 못한다는 점이었다.

 

이러한 점 때문에 매번 테스트 케이스를 부족한 영어를 총동원하여 작성했고 테스트가 수행되는 로그를 보면서 매번 머릿속에서 영어→한글로의 번역을 해야 되는 부담이 증가했다.

 

매번 테스트 케이스를 작성할 때 테스트 케이스 결과를 한글로 해결할 방법이 없는지 조사했는데 마침내 이 문제에 대한 해답을 찾게 되어 정리해두고자 한다.

 

테스트 케이스 한글 표시 불가?

SpringBoot를 사용하면서 잠깐 다뤄봤던 JUnit에서는 "DisplayName" 이라는 Annotation이 존재한다. TestCase에 대해 작성자가 직접 테스트 케이스를 어떤 식으로 표시할 것인지를 지원하는 Annotation이다.

해당 어노테이션은 다음과 같은 방식으로 사용하며 테스트 케이스에 대해 한글로도 표시가 가능하게 만든다.

@DisplayName("테스트 01")
class Test01 {
		...
} 

그런데 이전까지는 Python의 unittest 혹은 pytest는 JUnit5에서 제공하는 “@DisplayName”과 같은 기능을 하는 함수나 모듈이 없는 줄 알았다. 따라서 지금까지 Python 개발에 사용되는 테스트 케이스는 다음과 같이 영어를 최대한 활용하여 테스트의 의도를 나타내는 방식이 일반적이었다.

def test_addition():
    assert 1 + 1 == 2

def test_subtraction():
    assert 5 - 3 == 2

 

한글 표시 불가에 대한 문제점

그냥 영어로 작성하면 충분하지 않을까?"라고 생각했었다.  그러나 테스트 케이스를 작성할 때, 의도를 명확히 드러내는 방법을 고민해야 한다는 점과, 테스트 결과를 다시 읽고 이해하려면 번역 과정을 거쳐야 한다는 점이 생각보다 큰 부담으로 다가왔다. 

 

물론, 요즘은 ChatGPT나 Codeium 같은 AI 도구를 활용해 테스트 케이스를 작성하는 일이 한결 편해졌지만, 여전히 작성과 번역 과정에서 거쳐야 할 단계들이 존재한다는 점은 문제로 남아 있다.

 

테스트 케이스를 한글로 작성하는 방법

각설하고 이제 unittest와 pytest에서 테스트 케이스를 한글로 작성하는 방법에 대해 기술해보고자 한다. 이는 필자가 찾아낸 방법의 일환일 뿐이기에 이 방법이 정답이 아니라는 것을 먼저 밝힌다.

 

또한 후술 하겠지만 이 방법은 Docstring에 한글을 기입하는 것이 공통점이다.

 

테스트 함수에 한글을 직접적으로 쓰는 것도 방법 중 하나지만 현재 사용중인  Pycharm 에서 해당 부분에 노란색 밑줄로 체크를 해서 보기 불편함이 발생하니 찾아낸 방법이기도 하다.

테스트명을 한글로 작성하니 PyCharm에서 노란줄을 표시한다.

 

UnitTest에서의 한글로 표출하기

Unittest를 사용하는 경우. 테스트 케이스 결과를 한글로 표출하는 방법은 TextTestResult 클래스를 상속받아 startText Method를 Overriding 하는 것이다.

from unittest.runner import TextTestResult

class CustomTextTestResult(unittest.TextTestResult):
    def startTest(self, test):
        super(TextTestResult, self).startTest(test)
        if self.showAll:
            self.stream.write(test._testMethodDoc) # 추가된 부분
            self.stream.write(" ... ")
            self.stream.flush()
            self._newline = False

이에 더해 unittest는 테스트러너 클래스를 지정해 줄 수 있는데 위에서 정의한 CustomTextTestResult 클래스를 테스트러너 클래스를 상속받아 생성자에 넣어줘야 한다.

class CustomTextTestRunner(unittest.TextTestRunner):

    def __init__(self):
        super(CustomTextTestRunner).__init__(resultclass=CustomTextTestResult)

위의 두 가지 정도를 준비하면 테스트를 실행하는데 한글로 표기하는 준비가 끝났다. 이제 테스트 케이스 하나를 예시로 작성해 보자.

class TestCaseGroup(unittest.TestCase):

    def test_method01(self):
        """ 여기에 적힌 글자가 테스트 결과에 표시됩니다. """
        self.assertEqual(1, 1)
        
if __name__ == '__main__':
    unittest.main(testRunner=CustomTextTestRunner)

이제 shell에서 테스트를 실행해 보자.

╰─$ python -m unittest test_unittest_example.py -v
test_method01 (test_unittest_example.TestCaseGroup)
여기에 적힌 글자가 테스트 결과에 표시됩니다. ... ok

----------------------------------------------------------------------
Ran 1 test in 0.000s

OK

 

pytest에서의 한글로 표출하기

pytest의 경우는 unittest보다는 간단해서 놀라웠는데 pytest의 설정을 조정하는 파일인 conftest.py 파일에 “pytest_itemcolleced” 함수를 다음과 같이 작성하는 것이다.

def pytest_itemcollected(item: Function):
    """ change test name, using fixture names """

    target_object = item._obj
    if target_object:
        item._nodeid = f"{item.nodeid}:{getattr(target_object, '__doc__')}"

이제 다음과 같이 테스트 코드를 작성하고 pytest를 실행 보자.

def test_function01():
    """ 테스트 메서드를 한글로 노출 01"""
    assert 1 == 1

def test_function02():
    """ 테스트 메서드를 한글로 노출 02"""
    assert 1 == 1

결과는 다음과 같다.

─$ pytest  -v
================================================== test session starts ===================================================
platform darwin -- Python 3.10.12, pytest-8.1.1, pluggy-1.4.0 -- /Users/jako/private/git-repo/backend-playground-src/venv/bin/python
cachedir: .pytest_cache
rootdir: /Users/jako/private/git-repo/backend-playground-src/usage_libs/usage_testing
plugins: bdd-7.1.2, anyio-4.2.0
collected 3 items

test_function_example01.py::test_function01: 테스트 메서드를 한글로 노출 01 PASSED                                 [ 33%]
test_function_example01.py::test_function02: 테스트 메서드를 한글로 노출 02 PASSED                                 [ 66%]

이 예시는 함수로 작성된 테스트 코드인데 클래스로 작성된 예시는 어떨까?

class TestClassExample:

    def test_class_method01(self):
        """클래스 메서드를 한글로 노출 """
        assert 1

    def test_class_method02(self):
        """클래스 메서드를 한글로 노출 """
        assert 1
╰─$ pytest  -v
================================================== test session starts ===================================================
platform darwin -- Python 3.10.12, pytest-8.1.1, pluggy-1.4.0 -- /Users/jako/private/git-repo/backend-playground-src/venv/bin/python
cachedir: .pytest_cache
rootdir: /Users/jako/private/git-repo/backend-playground-src/usage_libs/usage_testing
plugins: bdd-7.1.2, anyio-4.2.0
collected 2 items

test_class_example01.py::TestClassExample::test_class_method01:클래스 메서드를 한글로 노출  PASSED                 [ 50%]
test_class_example01.py::TestClassExample::test_class_method02:클래스 메서드를 한글로 노출  PASSED                 [100%]

함수로 작성된 테스트 코드와 결과는 동일하다.

 

마치며

파이썬에서 테스트 케이스 결과를 한글로 표시되게 하는 문제는 꽤나 오랫동안 생각하며 쫓아다닌 문제이다. 처음 이 문제 상황에 대해 불편함을 느끼고 해결 방법에 대한 접근은 JUnit5의 “@DisplayName”과 같은 기능을 제공하는 함수나 클래스가 있는지를 찾아보는 것이었는데 매번 답은 나오지 않았다.

 

그러던 중 Django에서 TestCase를 작성하게 되면서 Django는 어떤 식으로 TestCase를 결과로 내보내는지 코드를 추적하던 도중 알게 되었다. UnitTest가 제공하는 클래스를 상속하여 기능을 재정의하고 있는 것을 힌트로 삼아 테스트 결과로 표시되는 부분에 함수명 대신 docstring으로 치환하면 되지 않을까 싶은 것이 아이디어였다.

 

묵혀둔 문제가 풀렸기에 속 시원한 느낌이다. 앞으로 종종 테스트 케이스를 작성할 때 오늘 정리한 내용을 최대한 이용해 보고 마주치는 문제들은 또 정리를 반복해 기록으로 남겨야겠다.

728x90
반응형