python पैच के साथ__इनित__ का मजाक उड़ाते हुए गैर-समझौता भाग



unit-testing mocking (1)

यहां समाधान:

import unittest
from mock import patch


class PortfolioConfig(object):
    ini_value = 10

    def __init__(self, maxtrades, name):
        self.maxtrades = maxtrades + 2
        self.name = name


class MREUnitTestBase(unittest.TestCase):
    @staticmethod
    def change_wrapper(class_to_wrap, override_constructor_properties=None, override_class_properties=None):
        method_to_wrap = class_to_wrap.__init__

        def wrapped(self, *args, **kwargs):
            for k, v in override_constructor_properties.items():
                kwargs[k] = v
            return method_to_wrap(self, *args, **kwargs)

        for k, v in override_class_properties.items():
            setattr(class_to_wrap, k, v)

        return wrapped


class PortfoloConfigTest(MREUnitTestBase):
    portfolio_override = {'maxtrades': 40}
    portfolio_override_properties = {'ini_value': 100}
    @patch.object(PortfolioConfig, '__init__', MREUnitTestBase.change_wrapper(PortfolioConfig, portfolio_override, portfolio_override_properties))

    def test_change_in_portfolio_config_by_test(self):
        p = program_run()  # running main program

        self.assertEqual(p.maxtrades, 42)  # was overridden by test
        self.assertEqual(p.name, 'hello')
        self.assertEqual(p.ini_value, 100)


# this is the program code
def program_run():
    p = PortfolioConfig(maxtrades=100, name='hello')
    return p

इस सवाल का पहले से ही उत्तर दिया गया है:

पैथन के मॉलिंग मॉड्यूल से @ पैच के साथ वर्ग के एक __init__ फ़ंक्शन को मैं कैसे नकली कर सकता हूं:

यही मैंने कोशिश की है:

import mock
from mock import patch

class ConfigPortfolio(object):
    name = None
    def __init__(self, name=None, number=None):
        self.name = name
        self.number = number



with patch.object(ConfigPortfolio, 'name') as mock_name:
    mock_name.__get__ = mock.Mock(return_value='mocked name')
    # here I will call some functions in the actual prograam, where ConfigPortfolio will be instantied and I want to makre sure name will stay patched.
    p = ConfigPortfolio(name='hello', number=3) # will be deeply hidden in a function.
    print p.name # this should have changed to mocked name
    print p.number # this needs to stay 3 as it is instantiated with, as it is not overwritten by the wrapper.

आउटपुट है

hello
3

पैच.ओबैज नाम बदलता नहीं है, क्योंकि __init__ क्लास गुण को फिर से __init__ करता है जो कि इनिट को कहा जाता है। मैं केवल एक विशिष्ट प्रॉपर्टी को कैसे ओवरराइड कर सकता हूं, जो कि __इनट__ में सेट है?

इस मामले में कठिनाई यह है कि यह एक ऐसा वर्ग है जहां __init__ को लिपटे जाने की जरूरत है और इसे किसी भी संपत्ति के साथ ओवरराइड किया जा सकता है। जब क्लास को वास्तविक परीक्षण में तत्काल किया जाता है (तात्कालिकता कोड में कहीं गहरा होता है, जहां पर इसका कोई नियंत्रण नहीं होता है), इससे कोई फर्क नहीं पड़ेगा कि मैं इसे कितना मूल्य देना चाहता हूं। यह वह पैमाना है जिसे मैं पैच में सेट करता हूं जो कोड से instantion मान को ओवरराइड करेगा I

अद्यतन करें:

मैंने एक नया उदाहरण बनाया है जो init फ़ंक्शन को लपेटता है और इसे इसके मूल्य पर ओवरराइड करना चाहिए। वर्तमान में हालांकि यह ऐसा नहीं करता है। इसे ठीक करने के लिए कोई सुझाव दिखाने की सराहना की जाती है।

import unittest
from mock import MagicMock, patch


# this is the main code over which I have no control
def mre_run():
    p = PortfolioConfig(n=100)
    return p.value

# the overriding doesn't seem to work yet
def spy_decorator(method_to_decorate):
    mock = MagicMock()

    def wrapper(self, *args, **kwargs):
        mock(*args, **kwargs)
        return method_to_decorate(self, *args, **kwargs)

    wrapper.mock = mock
    return wrapper


class PortfolioConfig(object):
    def __init__(self, n):
        self.value = n+2


class PotatoTest(unittest.TestCase):
    def test_something(self):
        wrp = spy_decorator(PortfolioConfig.__init__)
        with patch.object(PortfolioConfig, '__init__', wrp):
            result = mre_run() # somehow call it with n=40, the wrapper around PortfolioConfig should change the value.
        # foo.mock.assert_called_once_with(n=40)
        self.assertEqual(result, 42)


if __name__ == '__main__':
    unittest.main()




patch