मैं एकाधिक स्थिरता मानों पर परीक्षणों का एक ही सेट चलाने के लिए चाहता हूं, लेकिन मैं उन मानों को स्थिरता परिभाषा में "हार्डकोड" नहीं करना चाहता हूं।

मेरा उपयोग-मामला एकाधिक कार्यान्वयन वाला एक इंटरफ़ेस है और मैं प्रत्येक कार्यान्वयन पर समान परीक्षण चलाने के लिए चाहता हूं।

उदाहरण के लिए, my_code.py

class Interface:
   def method():
      pass

class Impl1(Interface):
   def method():
      return 1

class Impl2(Interface):
   def method():
      return 2

Test_interface.py:

def test_method(instance: Interface):
    assert type(instance.method()) == int

Test_impl1.py

from my_code import Impl1
@pytest.fixture
def instance():
    return Impl1()

Test_impl2.py

from my_code import Impl2
@pytest.fixture
def instance():
    return Impl2()

जाहिर है यह कोड काम नहीं करता है (क्योंकि स्थिरता "उदाहरण" नहीं मिला है)। मैं conftest.py . में कुछ इस तरह लिख सकता हूँ

@pytest.fixture(params=[Impl1(), Impl2()])
def instance(request):
   return requst.param

लेकिन मैं केवल Impl1 का परीक्षण करने के लिए test_impl1.py चलाने में सक्षम होना चाहता हूं। इसके अलावा, अगर मैं कभी भी Impl3 लिखने जा रहा हूं, तो मैं conftest.py को बदलना नहीं चाहता, मैं बस साधारण test_impl3.py जोड़ना चाहता हूं और क्या होगा यदि मेरा कार्यान्वयन पूरी तरह से अन्य पैकेज में है?

संक्षेप में, मैं फिक्स्चर की सूची से प्रत्येक मान के लिए अपने परीक्षणों का पुन: उपयोग करना चाहता हूं, लेकिन मैं रनटाइम में फिक्स्चर की इस सूची को बदलना चाहता हूं (उदाहरण के लिए उपलब्ध कार्यान्वयन के आधार पर)

0
mike0sv 5 सितंबर 2019, 02:50

1 उत्तर

सबसे बढ़िया उत्तर

अंत में यह काम किया, हालांकि यह सुनिश्चित नहीं है कि यह विश्वसनीय समाधान है या नहीं। test/common/test_common.py में मैंने अपने परीक्षण किए:

def test_method(instance: Interface):
    assert type(instance.method()) == int

में tests/common/conftest.py मेरे पास दिलचस्प चीजें हैं:

THIS_PACKAGE = 'tests/common/'

def create_instance_hooks(meta_fixture, name):
    tests_node_id = os.path.join(THIS_PACKAGE, '{}.py'.format(name))

    def pytest_runtest_protocol(item, nextitem):
        split = item.nodeid.split('::')
        filename, *test_name = split
        if filename == tests_node_id and 'instance' in item.fixturenames:
            func_name = meta_fixture.__name__
            meta = tuple(item.session._fixturemanager._arg2fixturedefs[func_name])
            item._request._arg2fixturedefs['instance'] = meta

    @pytest.hookimpl(hookwrapper=True)
    def pytest_collect_file(path, parent):
        outcome = yield
        result = outcome.get_result()

        if parent.parent is None:
            result.append(
                DoctestModule(os.path.join(parent.fspath, THIS_PACKAGE, 'conftest.py'), parent,
                              nodeid=os.path.join(THIS_PACKAGE, '{}_conf.py'.format(name))))

            result.append(Module(os.path.join(parent.fspath, THIS_PACKAGE, 'test_common.py'), parent,
                                 nodeid=tests_node_id))

    return pytest_runtest_protocol, pytest_collect_file

और tests/impl1/conftest.py में मेरे पास है

@pytest.fixture
def impl1_instance():
    return Impl1()


pytest_runtest_protocol, pytest_collect_file = create_instance_hooks(impl1_instance, 'impl1')

और tests/impl2/conftest.py में मेरे पास है

@pytest.fixture
def impl2_instance():
    return Impl2()


pytest_runtest_protocol, pytest_collect_file = create_instance_hooks(impl2_instance, 'impl2')

तो मूल रूप से जब tests/implN परीक्षण एकत्र किए जाते हैं, pytest_collect_file हुक tests/common/test_common.py से परीक्षण जोड़ता है और फिर जब उन्हें चलाया जाता है, तो pytest_runtest_protocol हुक implN_instance फिक्स्चर को इंस्टेंस फिक्सचर के रूप में जोड़ता है। इसलिए, यदि मैं केवल impl1 या impl2 चलाता हूं, तो परीक्षणों का एक सेट चलाया जाता है, और यदि मैं केवल pytest परीक्षण चलाता हूं, तो उपयुक्त जुड़नार के साथ परीक्षणों के दो सेट होते हैं

0
mike0sv 9 सितंबर 2019, 15:49