Reputation: 277
I have a class which uses a sqlite3 database and want to write a test suite for it. In particular, I want to check that sqlite3.Cursor.execute
is called with the correct SQL command. However, I have run into trouble with mocking this method since sqlite3.Cursor
seems to be written in C and thus the class is immutable. This means I can't just patch the execute method, but if I try to patch the whole class, the assert fails, saying that execute was never called.
Below is my best attempt so far, but the assert fails, saying that there was no call. I would appreciate some suggestions as to what I'm doing wrong. Thanks.
import sqlite3
class MyClass:
def __init__(self):
self.db = sqlite3.connect('somedb.db')
def query(self, sql_squery):
c = self.db.cursor()
c.execute(sql_query)
import unittest
import mock
import myclass
class MyClassTestCase(unittest.TestCase):
@patch('myclass.sqlite3.Cursor')
def test_query(self, mock_sql_cursor):
mc = myclass.MyClass()
mc.query('test')
mock_sql_cursor.execute.assert_called_with('test')
Upvotes: 1
Views: 1346
Reputation: 6575
Here goes another approach
You could patch out myclass.sqlite3
and mock the and then mock the return value of connect().cursor().execute
.
import unittest
from mock import patch
from myclass import MyClass
class MyClassTestCase(unittest.TestCase):
def test_query(self, mock_sql_cursor):
with patch('uploads.myclass.sqlite3') as mocksql:
mc = MyClass()
mc.query('test')
mock_sql_cursor.connect().cursor().execute.assert_called_with('test')
Answer inspired in this answer
Upvotes: 2
Reputation: 23711
sqlite3
is a C extension and you cannot patch C calls. Any way you should not to test sqlite3
behavior but just your how code the call sqlite3
module.
What you can do is to patch sqlite3.connect()
method and check if your code call the API in the correct way:
class MyClassTestCase(unittest.TestCase):
@patch('sqlite3.connect', autospec=True)
def test_query(self, mock_connect):
mock_cursor = mock_connect.return_value.cursor.return_value
mc = myclass.MyClass()
mc.query('test')
mock_cursor.execute.assert_called_with('test')
Note:
sqlite3.connect
absolute path and not myclass....
do the same thing but it is more clear (sqlite3.connect
and myclass.sqlite3.connect
are exactly the same reference)autospec=True
to avoid strange errors like explained in Autospeccingsqlite3
moduleUpvotes: 0