在SQLAlchemy中使用Python模拟库

7
我正在使用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)

如您在单元测试中所见,我无法测试从第session = DBSession()行开始的get_session()代码。到目前为止,在搜索后,我无法找出返回的模拟值是否也可以用于模拟函数调用 - 类似于,我模拟session对象并验证是否调用了session.connection()
上述编写单元测试用例的方法是否正确?是否有更好的方法?
1个回答

6

首先,您可以通过测试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的实现,只需测试您的包装器如何调用它。

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


1
感谢您的输入。我只是想知道如何模拟自定义对象,就像上面的例子一样。由于某些函数依赖于其他函数,我想使用模拟来确保这些函数被调用时传递了正确的参数。非常感谢您的帮助。 - user2430771

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接