Tox로 가상 환경을 관리하고 테스트를 자동화하는 방법

Reading Time: 6 minutes

많은 개발자가 Python에서 테스트를 표준화하고 자동화하기 위한 솔루션으로 tox를 사용합니다. 그러나 이 도구를 테스트 자동화에만 사용하면 도구의 성능과 달성할 수 있는 전체 범위에 심각한 제한이 있습니다. 예를 들어, tox는 “내 머신에서 작동한다(it works on my machine)”는 문제에 대한 훌륭한 솔루션이기도 합니다. 여기에는 다음과 같은 몇 가지 이유가 있습니다:

  • 다양한 파이썬 종속성 버전에 대해 테스트를 실행할 수 있습니다.
  • 환경 변수를 격리할 수 있습니다.
  • 설정 명령을 캡처하여 실행할 수 있습니다.

또한, 가장 중요한 것은 위에 나열된 작업을 Windows, macOS 및 Linux OS에서 수행할 수 있다는 것입니다. 이 튜토리얼에서는 tox의 작동 원리와 이를 사용하여 귀중한 리소스를 절약하는 방법을 자세히 살펴보겠습니다. 또한 구체적인 코드 예제를 통해 tox를 어떻게 활용할 수 있는지 소개하겠습니다.

tox란 무엇인가요?

tox 설명서를 읽고 그 내용을 액면 그대로 받아들인다면, tox는 단순히 가상 환경을 생성하여 Python 패키지를 테스트하는 데 필요한 종속성을 설치하는 데 사용되는 도구라고 생각할 수 있습니다.

문서에 따르면 “tox는 Python에서 테스트를 자동화하고 표준화하는 것을 목표로 합니다. 이는 Python 소프트웨어의 패키징, 테스트 및 릴리스 프로세스를 간소화한다는 더 큰 비전의 일부입니다.”라고 설명합니다. 이어서 “tox는 일반적인 가상 환경 관리 및 테스트 명령줄 도구입니다.”라고 명시되어 있습니다. 같은 문서에 있는 몇 가지 예제에서는 문서를 작성하고 개발 환경을 실행하는 데 tox가 사용되는 것을 보여줍니다.

그러나 tox는 특정 워크플로우를 자동화하고 가상 환경을 관리하기 위한 도구로 생각하는 것이 좋습니다. tox 문서에 제공된 구성 파일의 예는 다음과 같습니다.

# content of: tox.ini , put in same dir as setup.py
[tox]
envlist = py27,py36

[testenv]
# install pytest in the virtualenv where commands will be executed
deps = pytest
commands =
    # NOTE: you can run any command line tool here - not just tests
    pytest

이 파일은 Pytest만 설치하고 실행하지만, 문서에는 “테스트뿐만 아니라 모든 명령줄 도구를 여기에서 실행할 수 있습니다.”라고 명시되어 있습니다.

tox는 어떻게 작동되나요?

tox 설명서의 시스템 개요 섹션에는 워크플로우 다이어그램이 나와 있습니다(그림 1). 이 다이어그램은 워크플로우를 아래에 설명된 일련의 단계로 나누어 tox의 작동 방식을 보여줍니다.

  1. tox.ini 파일에 정의된 Python 버전을 사용하여 가상 환경을 생성합니다.
  2. tox.ini 파일의 deps 설정 아래에 나열된 종속성을 가상 환경에 설치합니다. 또한 프로젝트의 SDIST가 생성된 경우 설치합니다(선택 사항).
  3. 격리된 가상 환경에서 명령을 실행합니다. 명령은 명령 설정 아래에 나열됩니다.
  4. 각 환경의 결과를 사용자에게 반환합니다.
그림 1. tox의 워크플로 다이어그램. 출처: tox 문서

있습니다. tox에 전달할 수 있는 명령은 테스트를 실행하는 명령에 국한되지 않기 때문에 tox는 단순히 테스트를 표준화하고 자동화하기 위한 도구 그 이상입니다.

간단한 예제를 만들었습니다. 이를 따라 tox를 사용하는 방법을 알아보세요.

tox의 이점

이 섹션에서는 가상 환경을 관리하고 테스트를 포함한 워크플로우를 자동화하는 데 tox를 사용하면 얻을 수 있는 몇 가지 이점을 강조합니다.

협업 용이성

면접을 위해 집에 가져갈 과제를 받을 때마다 tox를 사용합니다. 과제에 액세스하려면 채용 회사의 개발자가 tox를 설치하고 실행하기만 하면 됩니다. 팀과 함께 작업할 때도 마찬가지입니다. 팀원들은 환경을 재현하거나 종속성을 설치할 필요가 없습니다. 이러한 모든 작업은 tox.ini 파일에서 처리됩니다.

지속적 통합 촉진

tox가 없으면 CI(지속적 통합) 스크립트가 가상 환경 생성과 패키지 종속성 설치를 모두 처리해야 합니다. 즉, tox 없이 빌드된 CI 스크립트는 더 복잡합니다. 이에 대해서는 아래에서 자세히 살펴보겠습니다.

종속성 충돌 위험 감소

각 작업에 대해 tox는 새로운 가상 환경을 생성합니다. 따라서 종속성 충돌이 발생할 가능성이 줄어듭니다. 예를 들어 애플리케이션을 실행하고 실행하는 데 필요한 종속성을 각각 두 개의 별도 가상 환경에 설치할 수 있습니다.

로컬 개발 중에 발생하는 톡스의 주요 약점 중 하나는 종속성의 변경 사항을 추적하지 못한다는 점입니다. 따라서 변경 사항이 있을 때마다 tox 환경을 다시 생성하는 것이 중요합니다. 이 작업은 tox를 실행할 때 -r 플래그를 전달하면 됩니다(py -m tox -r).

간단한 tox 사용 사례 예시

tox에 대한 이해를 돕기 위해 kurtispykes/tox_example GitHub 리포지토리에서 복제할 수 있는 간단한 예제를 만들었습니다. 이를 따라 tox를 사용하는 방법을 알아보세요.

├── __init__.py
├── .gitignore
├── LICENSE
├── README.md
├── string_reversal.py
├── test_string_reversal.py
├── tox.ini

tox 생태계의 중심에는 다음 세 가지 형태 중 하나로 제공되는 구성 파일이 있습니다:

tox.ini
setup.cfg
pyproject.toml

이 예제에서는 tox.ini를 사용하여 tox를 구성합니다. 내용은 다음과 같습니다:

[tox]
envlist = my_env
skipsdist = true

[testenv]
deps = pytest
commands = pytest

INI 파일 구조에 따르면 .ini 확장자를 사용하는 구성 파일은 “각각 [section] 헤더로 시작하는 섹션과 특정 문자열(= or : by default)로 구분된 키/값 항목으로 구성된 섹션으로 구성된다”고 명시되어 있습니다.

tox에서 섹션 헤더는 새로운 tox 환경으로 변환됩니다. 하지만 이 예제에서는 [tox] 헤더를 주목하세요. 이 헤더는 tox 실행에 대한 전역 설정을 구성합니다. 이 헤더에서 다양한 버전의 Python을 사용하여 테스트를 실행하도록 tox에 지시할 수 있습니다.

[tox] 헤더에는 두 가지 항목이 포함되어 있습니다:

  1. envlist – 명령줄에서 py -m tox를 실행할 때 어떤 환경을 실행할지 tox에 알립니다. 이 예제에서, envlist의 이름은 my_env입니다. 초기 톡스 실행 후에는 톡스가 가상 환경의 세부 정보를 추적하고 종속성을 다시 만들거나 다시 설치하지 않으므로 다른 실행이 훨씬 빠르게 실행됩니다.
  2. skipsdistsetup.py 또는 pyproject.toml이 없는 경우 skipsdist 플래그를 true로 설정합니다. 설정하지 않으면 오류가 발생합니다.

테스트하려는 버전(py27, py37)을 추가하여 다른 버전의 Python에 대해 패키지를 테스트할 수도 있습니다. 패키지를 테스트하려는 Python 버전이 사용자 환경에 설치되어 있어야 하며, 그렇지 않으면 오류가 발생합니다.

[testenv][testenv:NAME] 헤더는 tox의 테스트 환경을 정의하는 데 사용되며, 여기서 NAME은 특정 환경의 이름입니다. [testenv] (최상위 수준이라고 함)에 정의된 설정은 사용자가 재정의하지 않는 한 개별 환경에 자동으로 상속됩니다.

이 예에서는 개별 환경을 정의하지는 않지만 다음 두 항목을 설정합니다:

  1. deps – 코드를 실행하는 데 필요한 종속성입니다.
  2. commands – 현재 테스트 환경의 일부로 트리거할 명령입니다.

이제 구성이 정의되었으므로 모듈을 생성하고 테스트하여 톡스의 작동을 보여줄 수 있습니다. 이 예제를 위해 생성한 모듈은 문자열을 반전시키는 데 사용되는 함수가 포함된 string_reversal.py입니다.

# The contents of string_reversal.py
def reverse_string(text):
    reverse_text = text[::-1]
    return reverse_text

모듈이 올바르게 작동하는지 테스트하려면 다음 test_string_reversal.py 스크립트를 사용하세요:

# The contents of test_string_reversal.py
from string_reversal import reverse_string

def test_calculate_age():
    # Given
    text = "Hello World!"

    # When
    reversed = reverse_string(text)

    # Then
    assert reversed == "!dlroW olleH"

다음 단계는 tox.ini 파일이 저장된 동일한 디렉토리에서 tox를 실행하는 것입니다. 명령줄에서 다음 명령을 사용하여 tox를 실행합니다:

py -m to

출력은 그림 2에 표시된 것과 비슷해야 합니다.

그림 2. 성공적인 톡스 실행의 로그

이 예제에서는 Pytest를 사용했지만 다른 라이브러리를 사용하여 모듈을 테스트할 수 있습니다. 실제로 임의의 명령어를 실행할 수 있습니다.

머신 러닝 패키지 만들기

tox를 다양한 시나리오로 확장할 수도 있습니다. 예를 들어, 거래 데이터로 학습된 머신 러닝(ML) 모델을 사용하여 사기 거래 발생 시기를 예측할 수 있습니다. 전체 코드는 kurtispykes/fraud-detection-project GitHub 리포지토리에서 확인할 수 있습니다. ML 모델 패키지의 최상위 구조는 다음과 같습니다:

├── fraud_detection_model # Contains the code required to build the model
├── requirements
│   ├── requirements.txt
│   ├── test_requirements.txt
├── tests # Contains the unit tests for the model
├── LICENSE
├── MANIFEST.in
├── mypy.ini
├── publish_model.sh
├── pyproject.toml 
├── setup.py
├── tox.ini

ML 모델 패키지를 빌드하려면 몇 가지 종속성이 필요했습니다. 패키지 종속성을 더 잘 관리하려면 requirements.txt 파일을 만들어야 합니다.

이 프로젝트의 tox 구성 파일에는 tox가 실행할 수 있는 여러 환경이 포함되어 있습니다. 이러한 개별 환경은 모델 학습에 필요한 데이터 가져오기부터 학습된 모델을 Gemfury 리포지토리에 게시하는 것까지 다양합니다. 이는 톡스가 가상 환경을 관리하는 데 유용한 도구가 될 수 있음을 보여줍니다. tox.ini 파일의 일부 구성은 다음과 같습니다.

# Part of the tox.ini file; click on the GitHub link to view the entire file
[tox]
envlist = test_package, typechecks, stylechecks, lint
skipsdist = True

[testenv]
install_command = pip install {opts} {packages}

passenv =
	KAGGLE_USERNAME
	KAGGLE_KEY
	GEMFURY_PUSH_URL

[testenv:test_package]
deps =
	-rrequirements/test_requirements.txt

setenv =
	PYTHONPATH=.
	PYTHONHASHSEED=0

commands=
	python fraud_detection_model/train_pipeline.py
	pytest \
	-s \
	-vv \
	{posargs:tests/}

[testenv:train]
envdir = {toxworkdir}/test_package
deps =
	{[testenv:test_package]deps}

setenv =
	{[testenv:test_package]setenv}

commands=
	python fraud_detection_model/train_pipeline.py

[testenv:fetch_data]
envdir = {toxworkdir}/test_package

setenv = {[testenv:test_package]setenv}

commands =
	# fetch
	kaggle competitions download -c ieee-fraud-detection  -p ./fraud_detection_model/data/interim
	# unzip
	unzip ./fraud_detection_model/data/interim/ieee-fraud-detection.zip -d ./fraud_detection_model/data/interim

[testenv:publish_model]
envdir = {toxworkdir}/test_package
deps =
	{[testenv:test_package]deps}

setenv =
	{[testenv:test_package]setenv}

commands=
	python fraud_detection_model/train_pipeline.py
	./publish_model.sh .

setup.py 파일이 추가되었으므로 전역 tox 헤더에서 skipsdist 인수를 제거할 수 있습니다. 이 경우 제거하지 않은 이유는 모델을 패키징하기 전에는 가상 환경을 관리하는 데 여전히 tox가 사용되고 있었기 때문입니다.

글로벌 envlist(in the [tox] header)가 test_package, typechecks, stylechecks, lint를 호출하는 것을 볼 수 있습니다. 명령줄에서 py -m tox를 호출하면 이러한 각 환경이 생성되고 각 환경의 명령이 실행됩니다.

독립적으로 실행할 특정 환경을 선택하려면 다음 명령을 사용하십시오: 프레임워크의 전체 기능. 대신, 특정 워크플로우를 자동화하고 가상 환경을 관리하기 위한 도구로 tox를 생각하는 것이 좋습니다.

py -m tox -e NAME

NAME은 tox를 생성하려는 테스트 환경의 이름입니다.

프로덕션 환경에서 tox 사용 시 참고 사항

다양한 CI 플랫폼이 tox와 매우 잘 통합됩니다. ML 모델 예제에서는 지속적 통합을 위해 CircleCI를 사용합니다. Circle CI 구성 파일은 여러 가상 환경을 직접 생성하는 대신 tox를 호출합니다. 자세한 내용은 GitHub의 CircleCI 구성 파일을 참조하세요.

요약

이 포스팅에서는 파이썬에서 테스트를 표준화하고 자동화하는 것 이상의 용도로 tox를 사용하는 방법에 대해 설명했습니다. 테스트 자동화에만 tox를 사용하는 것은 프레임워크의 전체 기능을 심각하게 활용하지 못하는 것입니다. 그보다는 특정 워크플로우를 자동화하고 가상 환경을 관리하기 위한 도구로 tox를 생각하는 것이 좋습니다.

3월 20일부터 24일까지 열리는 NVIDIA GTC 2023에 무료로 등록하고 데이터 사이언스와 가속화 컴퓨팅이 어떻게 업무를 혁신하는지 자세히 알아보세요.

이 블로그에 열거된 SDK의 대부분의 독점 액세스, 얼리 액세스, 기술 세션, 데모, 교육 과정, 리소스는 NVIDIA 개발자 프로그램 회원은 무료로 혜택을 받으실 수 있습니다. 지금 무료로 가입하여 NVIDIA의 기술 플랫폼에서 구축하는 데 필요한 도구와 교육에 액세스하시고 여러분의 성공을 가속화 하세요.

Discuss (0)

Tags

답글 남기기

이메일 주소는 공개되지 않습니다. 필수 항목은 *(으)로 표시합니다