简体   繁体   中英

How to mock.patch MySQLdb.cursors?

class CanonDatabase:
    def __init__(self, clean_up_db=False):
        self.db = "tmg_canon_april_tokens"
        self.conn = create_connection(self.db)
        self.cur = self.conn.cursor(cursorclass=MySQLdb.cursors.DictCursor)

I am trying to mock.patch MySQLdb in order to pass the constructor.

@mock.patch.object(MySQLdb, '__init__')
class TestDatabase(unittest.TestCase):
    def setUp(self):
        super(TestDatabase, self).setUp()
        patch = mock.patch('atone_canon.Database.create_connection')
        mock_baz = patch.start()
        mock_baz.cursor.return_value = mock.MagicMock()

    def tearDown(self):
        super(TestDatabase, self).tearDown()
        mock.patch.stopall()

    def test_clean_table(self, mysql_mock):
        db = CanonDatabase()
        self.assertEqual(True, False)

However this fails with the following error message:

 File "atone_canon/Database.py", line 20, in __init__ self.cur = self.conn.cursor(cursorclass=MySQLdb.cursors.DictCursor) 

AttributeError: 'module' object has no attribute 'cursors'

I found a way:

If I insert this import in my unit test, without (!) even using it:

from MySQLdb.cursors import DictCursor

Then I no longer get the error, and I won't even have to mock.patch the MySQLdb wrapper:

# @mock.patch.object(MySQLdb, '__init__')
class TestDatabase(unittest.TestCase):
   ...

Not too happy with the solution. Generally I have difficulties with mocking classes that live outside my project (eg live in the virtualenv). I leave this open, so hopefully someone can show me how to mock these kind of classes.

First of all: make sure you have in Database.py

import MySQLdb.cursors

Otherwise your mentioned error will be raised even if you don't patch anything. If you want double check it add cur=MySQLdb.cursors.DictCursor at the top of __init__ and remove all patches: you will find the same error raised in the new line. That error will disappear if you load MySQLdb.cursors somewhere in your context before try to point MySQLdb.cursors.DictCursor . If you are wondered that you haven't see that error before is because in your production code you import MySQLdb.cursors before use CanonDatabase()

Now make a test where your constructor will pass and create_connection evil function don't try to connect anything can be obtained simply by patching just create_connection and anything else:

class TestSimpler(unittest.TestCase):
    @mock.patch('atone_canon.Database.create_connection')
    def test_base(self, mock_create_connection):
        db = CanonDatabase()
        self.assertIsNotNone(db)

Of course you can decorate test class if you want patch create_connection for every test methods.

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