developer tip

“python setup.py test”에서 unittest discover를 실행하는 방법은 무엇입니까?

optionbox 2020. 10. 30. 07:57
반응형

“python setup.py test”에서 unittest discover를 실행하는 방법은 무엇입니까?


python setup.py test.NET과 동등한 기능을 실행하는 방법을 알아 내려고 노력 python -m unittest discover입니다. run_tests.py 스크립트를 사용하고 싶지 않고 외부 테스트 도구 ( nose또는 같은 py.test) 를 사용하고 싶지 않습니다 . 솔루션이 python 2.7에서만 작동하면 괜찮습니다.

에서 setup.py, 나는 내가 뭔가를 추가 할 필요가 있다고 생각합니다 test_suite및 / 또는 test_loader설정 필드,하지만 난 제대로 작동하는 조합을 찾을 수 없습니다 :

config = {
    'name': name,
    'version': version,
    'url': url,
    'test_suite': '???',
    'test_loader': '???',
}

unittestPython 2.7에 내장 된 경우에만 가능 합니까?

참고로 내 프로젝트 구조는 다음과 같습니다.

project/
  package/
    __init__.py
    module.py
  tests/
    __init__.py
    test_module.py
  run_tests.py <- I want to delete this
  setup.py

업데이트 : 이것은 가능 unittest2하지만 만 사용하여 동등한 것을 찾고 싶습니다.unittest

에서 https://pypi.python.org/pypi/unittest2

unittest2에는 매우 기본적인 setuptools 호환 테스트 수집기가 포함되어 있습니다. setup.py에 test_suite = 'unittest2.collector'를 지정하십시오. 이렇게하면 setup.py가 포함 된 디렉토리의 기본 매개 변수로 테스트 검색이 시작되므로 아마도 가장 유용한 예입니다 (unittest2 / collector.py 참조).

지금은라는 스크립트를 사용하고 run_tests.py있지만 .NET 만 사용하는 솔루션으로 이동하여이 문제를 제거 할 수 있기를 바랍니다 python setup.py test.

run_tests.py제거 하고 싶은 항목 은 다음과 같습니다 .

import unittest

if __name__ == '__main__':

    # use the default shared TestLoader instance
    test_loader = unittest.defaultTestLoader

    # use the basic test runner that outputs to sys.stderr
    test_runner = unittest.TextTestRunner()

    # automatically discover all tests in the current dir of the form test*.py
    # NOTE: only works for python 2.7 and later
    test_suite = test_loader.discover('.')

    # run the test suite
    test_runner.run(test_suite)

py27 + 또는 py32 +를 사용하는 경우 솔루션은 매우 간단합니다.

test_suite="tests",

Setuptools를 사용하여 패키지 빌드 및 배포 에서 (강조) :

test_suite

unittest.TestCase 하위 클래스 (또는 이들 중 하나 이상을 포함하는 패키지 또는 모듈 또는 이러한 하위 클래스의 메서드)의 이름을 지정하는 문자열 또는 인수없이 호출 할 수있는 함수 이름을 지정 하고 unittest.TestSuite를 반환합니다 .

따라서 setup.pyTestSuite를 반환하는 함수를 추가합니다.

import unittest
def my_test_suite():
    test_loader = unittest.TestLoader()
    test_suite = test_loader.discover('tests', pattern='test_*.py')
    return test_suite

그런 setup다음 다음과 같이 명령 지정합니다 .

setup(
    ...
    test_suite='setup.my_test_suite',
    ...
)

이 작업을 수행하기 위해 구성이 필요하지 않습니다. 기본적으로 두 가지 주요 방법이 있습니다.

빠른 방법

당신의 이름을 변경 test_module.py하는 module_test.py(기본적으로 추가 _test특정 모듈에 대한 시험을 접미사로), 그리고 파이썬은 자동으로 찾을 수 있습니다. 이것을 다음에 추가하십시오 setup.py.

from setuptools import setup, find_packages

setup(
    ...
    test_suite = 'tests',
    ...
)

먼 길

현재 디렉토리 구조로 수행하는 방법은 다음과 같습니다.

project/
  package/
    __init__.py
    module.py
  tests/
    __init__.py
    test_module.py
  run_tests.py <- I want to delete this
  setup.py

에서 및 단위 테스트 스크립트 tests/__init__.py를 가져온 다음 테스트를 실행할 함수를 만듭니다. 에서 , 이런 일을 입력 :unittesttest_moduletests/__init__.py

import unittest
import test_module

def my_module_suite():
    loader = unittest.TestLoader()
    suite = loader.loadTestsFromModule(test_module)
    return suite

TestLoader클래스에는 loadTestsFromModule. dir(unittest.TestLoader)다른 것을보기 위해 달릴 수 있지만 이것은 사용하기 가장 간단합니다.

디렉토리 구조가 이와 같기 때문에에서 스크립트 test_module를 가져올 수 있기를 원할 것입니다 module. 이미이 작업을 수행했을 수도 있지만 그렇지 않은 경우에 대비하여 package모듈과 module스크립트를 가져올 수 있도록 부모 경로를 포함 할 수 있습니다 . 상단에 다음 test_module.py을 입력합니다.

import os, sys
sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), '..')))

import unittest
import package.module
...

그런 다음 마지막으로에 모듈을 setup.py포함하고 tests생성 한 명령을 실행합니다 my_module_suite.

from setuptools import setup, find_packages

setup(
    ...
    test_suite = 'tests.my_module_suite',
    ...
)

그런 다음 python setup.py test.

다음은 누군가가 참조로 만든 샘플 입니다.


한 가지 가능한 해결책은 /에 대한 test명령을 확장하는 것 입니다. 이것은 내가 선호하는 것보다 훨씬 복잡하고 총체적인 것처럼 보이지만 실행시 내 패키지의 모든 테스트를 올바르게 발견하고 실행하는 것 같습니다 . 나는 누군가가 더 우아한 해결책을 제공하기를 바라면서 이것을 내 질문에 대한 대답으로 선택하는 것을 보류하고 있습니다. :)distutilssetuptoolsdistributepython setup.py test

( https://docs.pytest.org/en/latest/goodpractices.html#integrating-with-setuptools-python-setup-py-test-pytest-runner에서 영감을 얻음 )

setup.py:

try:
    from setuptools import setup
except ImportError:
    from distutils.core import setup

def discover_and_run_tests():
    import os
    import sys
    import unittest

    # get setup.py directory
    setup_file = sys.modules['__main__'].__file__
    setup_dir = os.path.abspath(os.path.dirname(setup_file))

    # use the default shared TestLoader instance
    test_loader = unittest.defaultTestLoader

    # use the basic test runner that outputs to sys.stderr
    test_runner = unittest.TextTestRunner()

    # automatically discover all tests
    # NOTE: only works for python 2.7 and later
    test_suite = test_loader.discover(setup_dir)

    # run the test suite
    test_runner.run(test_suite)

try:
    from setuptools.command.test import test

    class DiscoverTest(test):

        def finalize_options(self):
            test.finalize_options(self)
            self.test_args = []
            self.test_suite = True

        def run_tests(self):
            discover_and_run_tests()

except ImportError:
    from distutils.core import Command

    class DiscoverTest(Command):
        user_options = []

        def initialize_options(self):
                pass

        def finalize_options(self):
            pass

        def run(self):
            discover_and_run_tests()

config = {
    'name': 'name',
    'version': 'version',
    'url': 'http://example.com',
    'cmdclass': {'test': DiscoverTest},
}

setup(**config)

Python's standard library unittest module supports discovery (in Python 2.7 and later, and Python 3.2 and later). If you can assume those minimum versions, then you can just add the discover command line argument to the unittest command.

Only a small tweak is needed to setup.py:

import setuptools.command.test
from setuptools import (find_packages, setup)

class TestCommand(setuptools.command.test.test):
    """ Setuptools test command explicitly using test discovery. """

    def _test_args(self):
        yield 'discover'
        for arg in super(TestCommand, self)._test_args():
            yield arg

setup(
    ...
    cmdclass={
        'test': TestCommand,
    },
)

Another less than ideal solution slightly inspired by http://hg.python.org/unittest2/file/2b6411b9a838/unittest2/collector.py

Add a module that returns a TestSuite of discovered tests. Then configure setup to call that module.

project/
  package/
    __init__.py
    module.py
  tests/
    __init__.py
    test_module.py
  discover_tests.py
  setup.py

Here's discover_tests.py:

import os
import sys
import unittest

def additional_tests():
    setup_file = sys.modules['__main__'].__file__
    setup_dir = os.path.abspath(os.path.dirname(setup_file))
    return unittest.defaultTestLoader.discover(setup_dir)

And here's setup.py:

try:
    from setuptools import setup
except ImportError:
    from distutils.core import setup

config = {
    'name': 'name',
    'version': 'version',
    'url': 'http://example.com',
    'test_suite': 'discover_tests',
}

setup(**config)

This won't remove run_tests.py, but will make it work with setuptools. Add:

class Loader(unittest.TestLoader):
    def loadTestsFromNames(self, names, _=None):
        return self.discover(names[0])

Then in setup.py: (I assume you're doing something like setup(**config))

config = {
    ...
    'test_loader': 'run_tests:Loader',
    'test_suite': '.', # your start_dir for discover()
}

The only downside I see is it's bending the semantics of loadTestsFromNames, but the setuptools test command is the only consumer, and calls it in a specified way.

참고URL : https://stackoverflow.com/questions/17001010/how-to-run-unittest-discover-from-python-setup-py-test

반응형