itinneed
itinneed

Reputation: 153

Mocked class and methods not being patched

I have a file, main.py, which contains one method, main():

from grab_api_tokens import GrabApiTokens

def main()
    grab_api_tokens = GrabApiTokens(site_one, site_two)
    site_one_token = grab_api_tokens.login_to_site_one
    site_two_token = grab_api_tokens.login_to_site_two

When trying to test this, I'm using:

import unittest
from unittest.mock import patch, Mock
import main

class TestMain(unittest.TestCase):
@patch('main.grab_apitokens.GrabApiTokens.login_to_site_two')
@patch('main.grab_apitokens.GrabApiTokens.login_to_site_one')
@patch('main.grab_apitokens.GrabApiTokens')
def test_main(self, mock_grab_api_tokens, mock_login_to_site_one, mock_login_to_site_two):
    mock_grab_api_tokens = Mock(ok=True)
    mock_login_to_site_one.return_value = "fake_token_one"
    mock_login_to_site_two.return_value = "fake_token_two"
    main.main()
    self.assertTrue(mock_grab_api_tokens.called)

the problem is that no matter how I change the @patch, I can't seem to get pycharm to recognize the mocked class. Calling main() just calls the plain main method, its not patching over the values I'm specifying. I can't see where I've gone wrong after reading the unittest documentation.

Upvotes: 3

Views: 874

Answers (1)

Lin Du
Lin Du

Reputation: 102257

The target you try to patch is not correct. Besides, you don't need to patch the properties of the GrabApiTokens class. You can patch the GrabApiTokens class and assign the fake data to the properties of its instance directly.

E.g.

main.py:

from grab_api_tokens import GrabApiTokens


def main():
    site_one = '123'
    site_two = '456'
    grab_api_tokens = GrabApiTokens(site_one, site_two)
    site_one_token = grab_api_tokens.login_to_site_one
    site_two_token = grab_api_tokens.login_to_site_two
    print('site_one_token: ', site_one_token)
    print('site_two_token: ', site_two_token)

grab_api_tokens.py:

class GrabApiTokens():
    def __init__(self, site_one, site_two) -> None:
        self.login_to_site_one = site_one
        self.login_to_site_two = site_two

test_main.py:

import unittest
from unittest.mock import patch, Mock
import main


class TestMain(unittest.TestCase):
    @patch('main.GrabApiTokens')
    def test_main(self, mock_grab_api_tokens):
        mock_instance = mock_grab_api_tokens.return_value
        mock_instance.login_to_site_one = "fake_token_one"
        mock_instance.login_to_site_two = "fake_token_two"
        main.main()
        self.assertTrue(mock_grab_api_tokens.called)


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

test result:

 ⚡  coverage run /Users/dulin/workspace/github.com/mrdulin/python-codelab/src/stackoverflow/66641783/test_main.py && coverage report -m --include="src/*"
site_one_token:  fake_token_one
site_two_token:  fake_token_two
.
----------------------------------------------------------------------
Ran 1 test in 0.001s

OK
Name                                            Stmts   Miss  Cover   Missing
-----------------------------------------------------------------------------
src/stackoverflow/66641783/grab_api_tokens.py       4      2    50%   3-4
src/stackoverflow/66641783/main.py                  9      0   100%
src/stackoverflow/66641783/test_main.py            13      0   100%
-----------------------------------------------------------------------------
TOTAL 

Upvotes: 1

Related Questions