"अजगर सेटअप थिंकपैड टेस्ट" से बिना खोज के कैसे चला जाए?


82

मैं यह पता लगाने की कोशिश कर रहा हूं कि python setup.py testइसके बराबर चलाने के लिए कैसे प्राप्त करें python -m unittest discover। मैं एक run_tests.py स्क्रिप्ट का उपयोग नहीं करना चाहता और मैं किसी भी बाहरी परीक्षण उपकरण (जैसे noseया py.test) का उपयोग नहीं करना चाहता । यह ठीक है अगर समाधान केवल अजगर 2.7 पर काम करता है।

में setup.py, मुझे लगता है कि मुझे विन्यास में test_suite/ और / या test_loaderफ़ील्ड में कुछ जोड़ने की आवश्यकता है , लेकिन मुझे ऐसा संयोजन नहीं मिल रहा है जो सही ढंग से काम करता हो:

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

क्या यह केवल unittestअजगर 2.7 में निर्मित का उपयोग करना संभव है ?

FYI करें, मेरी परियोजना संरचना इस प्रकार है:

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 में एक बहुत ही बुनियादी सेटपूल संगत परीक्षण कलेक्टर शामिल हैं। अपने setup.py में test_suite = 'unittest2.collector' निर्दिष्ट करें। यह डायरेक्टरी के डिफ़ॉल्ट मापदंडों के साथ सेटअप ओरिजिन के साथ टेस्ट डिस्कवरी शुरू करता है, इसलिए यह शायद एक उदाहरण के रूप में सबसे अधिक उपयोगी है (देखें unittest2 /CD.py)।

अभी के लिए, मैं बस नामक एक स्क्रिप्ट का उपयोग कर रहा हूं run_tests.py, लेकिन मैं उम्मीद कर रहा हूं कि मैं केवल समाधान का उपयोग करके इससे छुटकारा पा सकता हूं 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)

यहां आने वाले किसी भी व्यक्ति के लिए सावधानी का एक शब्द है। setup.py परीक्षण एक कोड 'गंध' माना जाता है और यह भी पदावनत करने के लिए सेट है। github.com/pytest-dev/pytest-runner/issues/50
यश गौरव

जवाबों:


44

यदि आप py27 + या py32 + का उपयोग करते हैं, तो समाधान बहुत सरल है:

test_suite="tests",

1
मैं चाहता हूं कि यह बेहतर काम करे, मैं इस मुद्दे में भाग गया: stackoverflow.com/questions/6164004/… "टेस्ट नामों को मॉड्यूल नामों से मेल खाना चाहिए। यदि" foo_test.py "परीक्षण है, तो एक संबंधित मॉड्यूल fx.py होना चाहिए। "
चार्ल्स एल।

1
मैं सहमत हूँ। मेरे मामले में, जहां मैं एक पायथन बाहरी परीक्षण कर रहा हूं, जहां शाब्दिक रूप से .py के साथ ऐसा कोई पायथन मॉड्यूल नहीं है, इसे प्राप्त करने का कोई अच्छा तरीका नहीं है।
टॉम स्विरली

2
यह सही उपाय है। मेरे पास @CharlesL मुद्दा नहीं था। था। मेरे सभी परीक्षणों के नाम हैं test_*.py। इसके अलावा मुझे पता चला कि यह वास्तव में किसी भी वर्ग को खोजने के लिए दिए गए निर्देशिका के माध्यम से पुनरावर्ती खोज करेगा unittest.TestCast। यह बेहद उपयोगी है यदि आपके पास एक निर्देशिका संरचना है जहां आपके पास है tests/first_batch/test_*.pyऔर tests/second_batch/test_*.py। आप बस निर्दिष्ट कर सकते हैं test_suite="tests",और यह सब कुछ पुनरावर्ती रूप से उठाएगा। ध्यान दें कि प्रत्येक नेस्टेड डायरेक्टरी को इसमें एक __init__.pyफाइल रखने की आवश्यकता होगी ।
dcmm88

39

से setuptools के साथ निर्माण और वितरित संकुल (जोर मेरा):

परीक्षण सूट

एक स्ट्रिंग एक unittest .estCase उपवर्ग (या एक पैकेज या उनमें से एक या अधिक, या इस तरह के एक उपवर्ग का एक मॉड्यूल) का नामकरण, या एक फ़ंक्शन का नामकरण जिसे बिना किसी तर्क के साथ बुलाया जा सकता है और एक unestest.TestSuite देता है

इसलिए, setup.pyआप एक फ़ंक्शन जोड़ेंगे जो एक TestSuite देता है:

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',
    ...
)

3
इस समाधान के साथ एक समस्या है, क्योंकि यह एकतरफा 2 "स्तर" बनाता है। मतलब यह है कि setuptools एक 'परीक्षण' कमांड बनाएगा जो setup.my_test_suite से एक TestSuite बनाने की कोशिश करेगा, जो इसे setup.py आयात करने के लिए मजबूर करेगा, जो फिर से सेटअप () चलाएगा! यह दूसरी बार एक नया (नेस्टेड) ​​टेस्ट कमांड बनाएगा जो आपके वांछित परीक्षण को चलाता है। यह ज्यादातर लोगों के लिए ध्यान देने योग्य नहीं हो सकता है, लेकिन यदि आप परीक्षण कमांड का विस्तार करने की कोशिश करते हैं (मुझे इसे संशोधित करने की आवश्यकता है क्योंकि मैं अपने परीक्षण 'इन-प्लेस' नहीं चला सकता) तो आप अजीब मुद्दों में भाग सकते हैं। इसके बजाय stackoverflow.com/a/21726329/3272850 का उपयोग करें
dcmm88

2
यह उपरोक्त कारणों से मेरे लिए परीक्षण दो बार चलाने का कारण बनता है। __init__.pyपरीक्षण फ़ोल्डर में फ़ंक्शन को स्थानांतरित करके और इसे संदर्भित करके इसे फिक्स्ड करें ।
बेनामी

3
दो बार निष्पादित किए जाने वाले परीक्षणों के मुद्दे को स्क्रिप्ट में ब्लॉक के setup()अंदर फ़ंक्शन निष्पादित करके आसानी से तय किया जा सकता है । पहली बार सेटअप स्क्रिप्ट निष्पादित की जा रही है, इसलिए यदि ब्लॉक कहा जाएगा; दूसरी बार सेटअप स्क्रिप्ट को एक मॉड्यूल के रूप में आयात किया जाएगा, इसलिए यदि ब्लॉक नहीं कहा जाएगा। if __name__ == '__main__':setup.py
फहराया

हम्म, मुझे एहसास है कि मेरे setup.py में वह test_suiteपैरामीटर बिल्कुल नहीं है , फिर भी "python setup.py test" अभी भी मेरे लिए ठीक काम करता है। यह बात अलग है कि डॉक्स क्या कहता है : "यदि आपने अपने सेटअप () कॉल में test_suite सेट नहीं किया है, और --test- सूट विकल्प प्रदान नहीं करते हैं, तो एक त्रुटि उत्पन्न होगी।" कोई उपाय?
रायलूओ जूल

21

यह काम करने के लिए आपको कॉन्फिग की आवश्यकता नहीं है। मूल रूप से इसे करने के दो मुख्य तरीके हैं:

त्वरित तरीका है

अपने नाम 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, आप unittestऔर आपकी इकाई परीक्षण स्क्रिप्ट आयात करना चाहते हैं test_module, और फिर परीक्षण चलाने के लिए एक फ़ंक्शन बनाएँ। इस tests/__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

यहाँ एक नमूना है जिसे किसी संदर्भ के रूप में बनाया गया है।


2
सवाल यह था कि कैसे "अजगर सेटअप थिंकपैड टेस्ट" बनाया जाए, जो यूनिटेस्ट की खोज क्षमता का उपयोग करे। यह पता नहीं है।
mikenerone

उह ... हाँ, मैंने पूरी तरह से सोचा था कि सवाल कुछ अलग पूछ रहा था। मुझे यकीन नहीं है कि यह कैसे हुआ, मुझे अपना दिमाग खोना चाहिए :(
एंटीमैटर

5

एक संभावित समाधान केवल और / के testलिए कमांड का विस्तार करना है । ऐसा लगता है कि कुल kluge और जिस तरह से मैं पसंद करूँगा उससे अधिक जटिल है, लेकिन लगता है कि सही ढंग से खोजने के लिए और चलाने पर मेरे पैकेज में सभी परीक्षणों को चलाने के लिए । मैं उम्मीद में मेरे सवाल के जवाब के रूप में इसे चुनने पर रोक रहा हूं कि कोई और अधिक सुरुचिपूर्ण समाधान प्रदान करेगा :)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)

3

Http://hg.python.org/unittest2/file/2b6411b9a838/unittest2/collector.py द्वारा प्रेरित आदर्श समाधान से थोड़ा कम

एक मॉड्यूल जोड़ें जो TestSuiteखोजे गए परीक्षणों की वापसी करता है। फिर उस मॉड्यूल को कॉल करने के लिए सेटअप कॉन्फ़िगर करें।

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

यहाँ है 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)

और यहाँ है 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)

3

पायथन का मानक पुस्तकालय unittestमॉड्यूल खोज का समर्थन करता है (पायथन में 2.7 और बाद में, और पायथन 3.2 और बाद में)। यदि आप उन न्यूनतम संस्करणों को मान सकते हैं, तो आप केवल discoverकमांड लाइन तर्क को जोड़ सकते हैंunittest

केवल एक छोटे ट्वीक की आवश्यकता है 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,
    },
)

BTW, मैं ऊपर मान रहा हूँ कि आप केवल पायथन संस्करणों को लक्षित कर रहे हैं जो वास्तविक समर्थन खोज (2.7 और 3.2+) है, क्योंकि विशेष रूप से इस सुविधा के बारे में सवाल है। यदि आप पुराने संस्करणों के साथ संगत रहना चाहते हैं, तो (जैसे कि उन मामलों में सेटपूल के मानक लोडर का उपयोग करके) आप निश्चित रूप से, संस्करण-जांच में सम्मिलित को लपेट सकते हैं।
mikenerone

0

यह run_tests.py को नहीं निकालेगा, लेकिन इसे सेटपूल के साथ काम करेगा। जोड़ें:

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

फिर setup.py में: (मुझे लगता है कि आप कुछ ऐसा कर रहे हैं setup(**config))

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

एकमात्र नकारात्मक पहलू जो मैं देख रहा हूं वह यह है कि यह शब्दार्थ को झुका रहा है loadTestsFromNames, लेकिन सेटप्टूलस टेस्ट कमांड एकमात्र उपभोक्ता है, और इसे निर्दिष्ट तरीके से कहता है ।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.