在 sqlalchemy 上使用 python 模拟库

Using python mocking library on sqlalchemy

我正在使用 sqlalchemy 查询我的数据库中的项目。同时,我是单元测试的新手,我正在尝试学习如何进行单元测试来测试我的数据库。我尝试使用模拟库进行测试,但到目前为止,它似乎非常困难。

所以我编写了一段代码来创建一个 Session 对象。该对象用于连接数据库。

from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.exc import OperationalError, ArgumentError

test_db_string = 'postgresql+psycopg2://testdb:hello@localhost/' \
                   'test_databasetable'
def get_session(database_connection_string):
    try:
        Base = declarative_base()
        engine = create_engine(database_connection_string)
        Base.metadata.bind = engine
        DBSession = sessionmaker(bind=engine)
        session = DBSession()
        connection = session.connection()
        return session
    except OperationalError:
        return None
    except ArgumentError:
        return None

所以我为这个功能做了一个单元测试用例:

import mock
import unittest
from mock import sentinel
import get_session

class TestUtilMock(unittest.TestCase):

    @mock.patch('app.Utilities.util.create_engine')  # mention the whole path
    @mock.patch('app.Utilities.util.sessionmaker')
    @mock.patch('app.Utilities.util.declarative_base')
    def test_get_session1(self, mock_delarative_base, mock_sessionmaker,
                         mock_create_engine):
        mock_create_engine.return_value = sentinel.engine
        get_session('any_path')
        mock_delarative_base.called
        mock_create_engine.assert_called_once_with('any_path')
        mock_sessionmaker.assert_called_once_with(bind=sentinel.engine)

如您在我的单元测试中所见,我无法测试 get_session() 中从第 session = DBSession() 行开始的代码。到目前为止,在谷歌搜索之后,我无法确定返回的模拟值是否也可以用于模拟函数调用——比如,我模拟 session 对象并验证我是否调用了 session.connection()

上面写单元测试用例的方法对吗?有更好的方法吗?

首先你可以通过

测试session = DBSession()
self.assertEqual(get_session('any_path'), mock_sessionmaker.return_value.return_value)

此外,mock_delarative_base.called 不是断言,也不会失败。替换为

self.assertTrue(mock_delarative_base.called)

一般注意事项

像这样编写测试可能非常耗时,并且会使您的生产代码真正与测试代码耦合。最好编写自己的包装器,为您的业务代码提供一个舒适的界面,并使用一些模拟和真实(简单)测试对其进行测试:您应该信任 sqlalchemy 实现并测试您的包装器如何调用它

在你可以通过一个你可以控制的假对象模拟你的包装器或使用模拟并检查你的代码如何调用它之后,你的包装器将只提供一些业务接口并且模拟它应该非常简单。