简体   繁体   中英

How to mock class instance in unit test of this class instance method

Im trying to unittest some_function which is MyClass instance method that requires someapi.api instance . How do I patch self.api.something1.something2(foo) with some return value?

import someapi

class MyClass(object):

  def __init__(self,a,b):
    self.a = a
    self.b = b
    self.api = someapi.api(self.a, self.b)

  def some_function(self, foo):
    result = self.api.something1.something2(foo)

    new_result = dosomething(result)
    return new_result

So really what I want is to mock response of this api so I can test that dosomething(result) does what I want.

@mock.patch('self.api.something1.something2', side_effect='something')
def testGet_circuits(self,pymock):
    result = some_function('foobar')
    expected_result= 'something'
    self.assertEqual(result, 'expected_result')

I tried

@mock.patch('someapi.api')
def testSome_function(self,someapi_mock):
    api = MyClass('a','b')
    result = api.some_function('foo')
    self.assertEqual(result,'newfoo')

What I'm strugling with is how to mock self.api.something1.something2(foo) inside some_function :(

You are not setting up your mock properly. I crafted an example using your code and managed to put together a test method that works. Ultimately, what is happening here is that you are not telling your mocks how to behave when the code runs. You start off probably mocking in the right place, but beyond that, the mock itself no longer has any of the attributes you are trying to access in order to allow the code to run. I'll go through the code to help illustrate:

class TestStuff(unittest.TestCase):

    @mock.patch('real_code.someapi.api', autospec=True)
    def testSome_function(self, someapi_mock):

        someapi_mock.return_value.something1 = mock.Mock(spec=Something)

        someapi_mock.return_value.something1.something2.return_value = 'newfoo'

        api = MyClass('a', 'b')
        result = api.some_function('foo')
        self.assertEqual(result, 'newfoo')

First thing, notice that I'm mocking more with respect to where I am testing, which is important to keep in mind, and you should read about here .

For the mock configuration issue, I can only assume from your real code, api.something1.something2 indicates that something1 is holding the instance of some other class that gives you access to the something2 method. So, the example is being illustrated with that assumption.

Now, as you can see within the first line of the method, what I'm doing is telling my mock to ensure it has the something1 attribute. It is important to remember that when you are mocking, and even when you set the spec and/or autospec (as I have used in my example), you don't get access to the attributes created in your __init__ . So you need to provide them in your mock per my example.

The second line now goes the next step to mock out the something2 method behaviour you are trying to get a result from. With this done, when your real code is called, it should go through the expected behaviour you set up and return the expected newfoo value.

To further help, here is the exact code I used to help put together that functional test:

real_code.py

import someapi


class MyClass(object):

  def __init__(self,a,b):
    self.a = a
    self.b = b
    self.api = someapi.api(self.a, self.b)

  def some_function(self, foo):
    result = self.api.something1.something2(foo)

    new_result = dosomething(result)
    return new_result


def dosomething(foo):
    return foo

someapi.py

class api:
    def __init__(self, a, b):
        self.a = a
        self.b = b
        self.something1 = Something()


class Something:

    def something2(self, some_arg):
        return some_arg

Thanks for all the answers definitely helped me I ended up doing below and worked like a charm . This whole mock thing looks like rabbit hole and i need to go deeper to fully understand.

@mock.patch('someapi.api')
def testSome_function(self,someapi_mock):
    someapi_mock = return_value.something1.something2.return_value = 'mocked_value'
    api = MyClass('a','b')
    result = api.some_function('foo')
    self.assertEqual(result,'newfoo')

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