Как макетировать методы для базы данных - PullRequest
0 голосов
/ 18 декабря 2018

Я новичок в Python и вообще издеваюсь.Поэтому я попытался найти решение своей проблемы, прочитав документацию: https://docs.python.org/3/library/unittest.mock.html#magic-methods, в следующей статье: http://alexmarandon.com/articles/python_mock_gotchas/ и множество вопросов о stackoverflow.Но я пока не смог найти решение.

Я пытаюсь смоделировать две функции, которые создают соединение с базой данных и помещают данные в pandas dataFrame.Они используются в пост-функции (перезаписывает пост-функцию django):

def post(self, request, *args, **kwargs):
    db_connection = du_db.get_connection(dbtype='mssql', username=crd.MS_SQL_USER, password=crd.MS_SQL_PWD)
    df = du_db.fetch_dataframe(sql, connection=db_connection)

В тестовой среде get_connection не должен возвращать ничего, а fetch_dataframe должен возвращать кадр данных pandas, определенный ранее.

Мой класс тестирования выглядит следующим образом:

class IndexViewTest(TestCase):

@mock.patch('du_db.db.get_connection')
@mock.patch('du_db.db.fetch_dataframe')
def setUp(self, mock_get_connection, mock_fetch_dataframe):
    self.c = Client()
    mock_get_connection = mock_get_connection()
    mock_fetch_dataframe = mock_fetch_dataframe()
    mock_get_connection.return_value = ""
    df = {'lot_of_data': ['xy', 'z'], 'more_data': [8, 9]}
    mock_fetch_dataframe.return_value = pd.DataFrame(df)
    assert mock_get_connection is data_utils.db.get_connection()
    assert mock_fetch_dataframe is data_utils.db.fetch_dataframe()
    assert mock_get_connection.called
    assert mock_get_connection.called

# Lot of test-functions similar to this:
def test_valid_data(self):
    resp = self.c.post('/', data={'id': 3338})
    self.assertEqual(resp.status_code, 200)
    self.assertContains(resp, 'Hello', status_code=200)

Я получаю следующее сообщение об ошибке:

enter image description here

Замена оригинальных функций через макеты не сработает.

Спасибо за вашу помощь.

1 Ответ

0 голосов
/ 18 декабря 2018
class IndexViewTest(TestCase):

    @mock.patch('du_db.db.get_connection')
    @mock.patch('du_db.db.fetch_dataframe')
    def setUp(self, mock_fetch_dataframe, mock_get_connection):
        self.c = Client()
        mock_get_connection = mock_get_connection() # remove this
        mock_fetch_dataframe = mock_fetch_dataframe() # remove this

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

        mock_get_connection.return_value = "" # this is NOT the mock you think
                                              # unless removing lines above.
                                              # And so on...
        df = {'lot_of_data': ['xy', 'z'], 'more_data': [8, 9]}
        mock_fetch_dataframe.return_value = pd.DataFrame(df)

        # data__utils or du_db ??
        assert mock_get_connection is data_utils.db.get_connection()                                                                 
        assert mock_fetch_dataframe is data_utils.db.fetch_dataframe()
        assert mock_get_connection.called
        assert mock_get_connection.called

    # Lot of test-functions similar to this:
    def test_valid_data(self):
        resp = self.c.post('/', data={'id': 3338})
        self.assertEqual(resp.status_code, 200)
        self.assertContains(resp, 'Hello', status_code=200)

Редактировать: Из того, что я понимаю, вы уже видите макеты на работе из pdb.Чтобы тесты работали так, как вам нравится, вам необходимо исправить каждую тестовую функцию, которая использует эти две функции, например, с помощью декораторов.Затем вы должны настроить макеты внутри исправленных тестовых функций.Также обычно вы утверждаете в тестах, но не в setUp.Я понимаю, что вы сделали это здесь просто для удобства, поскольку у вас были некоторые сомнения по поводу работающего кода.

Если вы думали о настройке макетов в setUp для использования другими тестовыми функциями (вы не можете этого сделатьТочно так же вам придется хранить их самостоятельно, а затем снова управлять ими в тестовых функциях), возможно, вас заинтересует этот пример из документации Mock:

Альтернативный способ управления исправлениями - этоиспользовать методы патча: запуск и остановка.Это позволяет вам переместить исправление в ваши методы setUp и tearDown.

>>> class MyTest(TestCase):
    ...
    def setUp(self):
        ...
        self.patcher = patch(’mymodule.foo’)
        ...
        self.mock_foo = self.patcher.start()
    ...
    ...
    def test_foo(self):
        ...
        self.assertTrue(mymodule.foo is self.mock_foo)
        ...
        ...
    def tearDown(self):
        ...
        self.patcher.stop()
        ...
>>> MyTest(’test_foo’).run()
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...