как провести модульное тестирование соединения с базой данных pymysql в python?

Я пытаюсь написать модульный тестовый пример, чтобы протестировать следующий метод, издеваясь над базой данных. Как имитировать соединение с базой данных без фактического подключения к реальному серверу базы данных. Я пробовал с тестовым примером. Я не уверен, что это правильный способ сделать это. Пожалуйста, поправьте меня, если я ошибаюсь.

//MySQL.py
    class MySQL():

        retry_interval = 20000 

        def link(self, server,port):
            try:
                return pymysql.connect(server, username='name', passwd='pwd', db='demo', int(port))
                sys.stdout.write('Connected to database at {}:{}\n'.format(server,port))
            except:
                sys.stderr.write('Retry database connection in {} ms...\n'.format(self.retry_interval))
                sleep(self.retry_interval/1000.0)
                continue

//test.py
from unittest.mock import Mock, MagicMock
from unittest.mock import patch
import MySQL

   @patch('MySQL.pymysql')
    def testLink(self, mysql_mock):
        mock_cursor = Mock.MagicMock()
        mysql_mock.connect.return_value.cursor.return_value.__enter__.return_value = mock_cursor

person user2301    schedule 06.11.2017    source источник
comment
Ограничения юнит-теста заканчиваются там, где достигается край вашего кода. В вашем случае pymysql.connect выходит за рамки модульного теста и должен быть высмеян. Что вы должны проверить, так это правильность вызова макета.   -  person Klaus D.    schedule 06.11.2017
comment
@Клаус Д. хорошо спасибо. попытаюсь   -  person user2301    schedule 06.11.2017


Ответы (1)


Единственная полезная вещь, которую вы действительно можете протестировать в MySQL.pymysql, — это метод connect, так что вы можете пропатчить его напрямую:

//test.py
from unittest.mock import Mock, MagicMock
from unittest.mock import patch, call
import MySQL

@patch('MySQL.pymysql.connect')
def testLink(self, connect_mock):
    # You can configure a return value for the connection if you need to...
    connect_mock.return_value = MagicMock(name='connection_return', return_value=...)

    # You can now test that your connection is being called...
    self.assertEqual(1, connect_mock.call_count)

    # You can also check the call parameters...
    self.assertEqual(connect_mock.call_args_list[0], call(server, username='name', passwd='pwd',...))
person DatHydroGuy    schedule 06.11.2017
comment
Привет Спасибо за помощь. Я пробовал так же, как показано в примере кода. Но я в замешательстве. Должен ли я издеваться над ссылкой на функцию или только над вызовом pymysql.connect? - person user2301; 07.11.2017
comment
@patch('MySQL.pymysql.connect') дает неиспользуемый импорт и SyntaxError: аргумент без ключевого слова после ключевого слова arg - person user2301; 07.11.2017
comment
Привет. Я не думаю, что вам нужно издеваться над функцией link, чтобы проверить код, который вы дали. Вы бы смоделировали функцию pymysql.connect, а затем ваш тест вызвал бы функцию link, которая вернула бы смоделированный объект подключения. - person DatHydroGuy; 07.11.2017
comment
SyntaxError, скорее всего, вызван порядком ваших аргументов в объявлении вашего метода (см. здесь подробности). Попробуйте переставить аргументы pymysql.connect так, чтобы именованные аргументы (имя пользователя, пароль, БД) шли после позиционных аргументов (сервер и порт). - person DatHydroGuy; 07.11.2017
comment
Хорошо спасибо. Я исправил эту синтаксическую ошибку. Но я всегда получаю эту ошибку ImportError: No module named pymysql. Я установил pymysql. Это правильный способ указать в патче @patch('MySQL.pymysql.connect')? - person user2301; 07.11.2017
comment
Ошибка ImportError, подобная той, которую вы упомянули, может быть вызвана тем, что ваш $PYTHONPATH не содержит путь к модулю, который вы пытаетесь импортировать. Это может отличаться от пути скрипта, который вы пытаетесь выполнить, поэтому перепроверьте их. Дополнительную информацию можно найти здесь. - person DatHydroGuy; 07.11.2017