I am writing some tests, using @patch. Seemingly the patch works, and the object I have patched should be called several times with multiple arguments, but it doesn't and I am not sure why.
class testMysqlBase(mySQLTestCase):
def setUp(self):
super().setUp()
def tearDown(self) -> None:
return super().tearDown()
@patch("mysql.connector.connection.MySQLConnection")
def test_exception_create_db_called_if_no_db(self, mysql_cnx) -> None:
mysql_db_ex = MysqlDBExecutor(mysql_cnx, "test_db")
mysql_cnx.cursor.return_value.__enter__.return_value = mysql_cnx.cursor
mysql_cnx.cursor.return_value.__enter__.return_value.execute.side_effect = [
(mysql.connector.errors.DatabaseError(errno=errorcode.ER_BAD_DB_ERROR)),
None,
None,
None,
mysql_db_ex.execute("test")
mysql_cnx.cursor.execute.assert_called_with(
["USE test_db;",
"CREATE DATABASE IF NOT EXISTS test_db",
"USE test_db;",
"test"]
)
from re import I
import mysql.connector
from mysql.connector import errorcode
class MysqlDBExecutor:
logger: Logger = getLogger(__name__)
def __init__(self, cnx: mysql.connector.connection, db: str):
self.cnx = cnx
self.db = db
def execute(self, cmd) -> None:
with self.cnx.cursor() as mycursor:
try:
mycursor.execute("USE " + self.db + ";")
except mysql.connector.Error as err:
if err.errno == errorcode.ER_BAD_DB_ERROR:
self.create_mysql_db()
mycursor.execute("USE " + self.db + ";")
else:
raise err(
f"Exception thrown in mysqlDBExecutor.execute on {self.db}"
)
try:
mycursor.execute(cmd)
except mysql.connector.Error as err:
raise err(f"Exception thrown in mysqlDBExecutor.execute on {self.db}")
def create_mysql_db(self) -> None:
mysql_query = "CREATE DATABASE IF NOT EXISTS {}".format(self.db)
with self.cnx.cursor() as mycursor:
try:
mycursor.execute(mysql_query)
except mysql.connector.Error as err:
raise err(
f"mysql Exception thrown in mysqlExecutor creating db{self.db}"
)
except Exception:
raise
So in the test, when I call mysql_db_ex.execute
on the database which doesn't exist the patched mysql_cnx
cursor has a DatabaseError side_effect the first time round, which gets caught, calling self.create_mysql_db()
In there the cursor is called again to create the database, then the database is used and finally the command cmd
should be issued. So it should get called 4 times, but i get;
E AssertionError: expected call not found.
E Expected: execute(['USE test_db;', 'CREATE DATABASE IF NOT EXISTS test_db', 'USE test_db;', 'test'])
E Actual: execute('test')
Can anyone explain where I am going wrong? I know the mysql_cnx.cursor.execute gets called 4 times, with those argyuments - so I am a bit confused.
https://docs.python.org/3/library/unittest.mock.html#unittest.mock.Mock.assert_called_with
This method is a convenient way of asserting that the last call has been made in a particular way
assert_called_with only checks the last call made, you are trying to use it to do 4 separate call checks.
You probably want to use https://docs.python.org/3/library/unittest.mock.html#unittest.mock.Mock.assert_has_calls