简体   繁体   中英

How to patch instances in __init__ method of a class?

I am writing a unittest. How can I patch self.conf in the init method in class MyValidator? In my unittest, I want to create a fake self.conf and get the response to make assertion of each element in self.conf.

class MyValidator(wsgi.Middleware):

    def __init__(self, app):
        self.app = app
        self.conf = {
            'auth_uri': CONF.someuri
            'admin_domain_name': CONF.somedomainname,
            'admin_user': CONF.someuser,
            'admin_password': CONF.get_admin_password(),
            'domain_name': CONF.somedomainname
        }

For unittest, I am thinking to do.. (I know this is wrong.. but you get the idea)

@mock.patch('my_module.MyValidator.__init__.conf')
def setUp(self, mock_config):
    @webob.dec.wsgify()
    def fake_app(req):
        return webob.Response()
    self.request = webob.Request.blank('/')
    mock_config = {
        'auth_uri': 'testuri'
         ....
         ....
    }
    self.middleware = MyValidator(fake_app)

def test_auth_uri(self):
    auth_uri = 'testuri'
    env_auth_uri = self.request.environ.get('auth_uri', None)
    self.assertEqual(auth_uri, env_auth_uri)

What should be done to patch self.conf to get intended response?

Even I'm using mocking and patching extensively I don't think your case need it. conf is a MyValidator 's public attribute and you don't need anything more than change it as you need.

def setUp(self):
    @webob.dec.wsgify()
    def fake_app(req):
        return webob.Response()
    self.request = webob.Request.blank('/')
    self.middleware = MyValidator(fake_app)
    self.middleware.conf = {
        'auth_uri': 'testuri'
         ....
         ....
    }

In this case patch cannot give to you nothing more because you are not interested about dict access and some smaller context where changes are made. If in some other test you need some other values you can use either self.middleware.conf.update(...) or self.middleware.conf[...]=... without change the behavior of other tests because setUp() configure it in the same way for every tests.

Things become different if conf is a read only property of MyValidator (a little bit better design). In this case you need to patch it to make your test:

class MyValidator(wsgi.Middleware):
    def __init__(self, app):
        self.app = app

    @property
    def conf(self):
        return {
            'auth_uri': CONF.someuri
            'admin_domain_name': CONF.somedomainname,
            'admin_user': CONF.someuser,
            'admin_password': CONF.get_admin_password(),
            'domain_name': CONF.somedomainname
        }

Where the test class should be

@mock.patch('my_module.MyValidator.conf', new_callable=PropertyMock)
def setUp(self, mock_conf):
    @webob.dec.wsgify()
    def fake_app(req):
        return webob.Response()
    self.request = webob.Request.blank('/')
    mock_conf.return_value = {
        'auth_uri': 'testuri'
         ....
         ....
    }
    self.middleware = MyValidator(fake_app)

def test_auth_uri(self):
    auth_uri = 'testuri'
    env_auth_uri = self.request.environ.get('auth_uri', None)
    self.assertEqual(auth_uri, env_auth_uri)

Patch __init__() is useful in rare cases. For instance when __init__ do some work and need resources that cannot be used or will not be used in test environment. An example of it is when init try to access to databases, use network resources, start new thread and so on.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM