在sqlalchemy上使用python模拟库

use*_*771 5 python unit-testing sqlalchemy mocking python-mock

我正在使用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
Run Code Online (Sandbox Code Playgroud)

因此,我为此功能制作了一个单元测试用例:

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)
Run Code Online (Sandbox Code Playgroud)

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

以上编写单元测试用例的方法正确吗?有更好的方法吗?

Mic*_*ico 5

首先,您也可以session = DBSession()通过以下方式测试线路

self.assertEqual(get_session('any_path'), mock_sessionmaker.return_value.return_value)
Run Code Online (Sandbox Code Playgroud)

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

self.assertTrue(mock_delarative_base.called)
Run Code Online (Sandbox Code Playgroud)

一般注意事项

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

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