【问题标题】:Mock a MySQL database in Python在 Python 中模拟 MySQL 数据库
【发布时间】:2015-04-10 11:20:13
【问题描述】:

我使用 Anaconda 发行版中的 Python 3.4。在这个发行版中,我发现pymysql 库可以连接到位于另一台计算机上的现有 MySQL 数据库。

import pymysql
config = {
      'user': 'my_user',
      'passwd': 'my_passwd',
      'host': 'my_host',
      'port': my_port
    }

    try:
        cnx = pymysql.connect(**config)
    except pymysql.err.OperationalError : 
        sys.exit("Invalid Input: Wrong username/database or password")

我现在想为我的应用程序编写测试代码,我想在每个测试用例的setUp 处创建一个非常小的数据库,最好在内存中。但是,当我突然尝试使用 pymysql 时,它无法建立连接。

def setUp(self):
    config = {
      'user': 'test_user',
      'passwd': 'test_passwd',
      'host': 'localhost'
    }
    cnx = pymysql.connect(**config)

pymysql.err.OperationalError: (2003, "Can't connect to MySQL server on 'localhost' ([Errno 61] Connection refused)")

我一直在谷歌搜索,发现了一些关于SQLiteMySQLdb 的信息。我有以下问题:

  1. sqlite3MySQLdb 是否适合在内存中快速创建数据库?
  2. 如何在 Anaconda 包中安装 MySQLdb
  3. 是否有在setUp 中创建的测试数据库示例?这是个好主意吗?

我的计算机上没有本地运行的 MySQL 服务器。

【问题讨论】:

  • 答案很可能是获取一个在本地运行的mysql db。 SQLite 与 mysql 有很多不同,所以用 SQLite 代替 mysql 并不是一个好的测试。

标签: python mysql sqlite mysql-python pymysql


【解决方案1】:

您可以使用 testing.mysqld (pip install testing.mysqld) 模拟 mysql 数据库

由于一些noisy error logs that crop up,我在测试时喜欢这个设置:

import testing.mysqld
from sqlalchemy import create_engine

# prevent generating brand new db every time.  Speeds up tests.
MYSQLD_FACTORY = testing.mysqld.MysqldFactory(cache_initialized_db=True, port=7531)


def tearDownModule():
    """Tear down databases after test script has run.
    https://docs.python.org/3/library/unittest.html#setupclass-and-teardownclass
    """
    MYSQLD_FACTORY.clear_cache()


class TestWhatever(unittest.TestCase):

    @classmethod
    def setUpClass(cls):
        cls.mysql = MYSQLD_FACTORY()
        cls.db_conn = create_engine(cls.mysql.url()).connect()

    def setUp(self):
        self.mysql.start()
        self.db_conn.execute("""CREATE TABLE `foo` (blah)""")

    def tearDown(self):
        self.db_conn.execute("DROP TABLE foo")

    @classmethod
    def tearDownClass(cls):
        cls.mysql.stop()  # from source code we can see this kills the pid

    def test_something(self):
        # something useful

【讨论】:

    【解决方案2】:

    pymysql、MySQLdb 和 sqlite 都需要一个真正的数据库来连接。 如果你只想测试你的代码,你应该在你想测试的模块上模拟 pymysql 模块,并相应地使用它 (在您的测试代码中:您可以设置模拟对象以将硬编码结果返回到预定义的 SQL 语句)

    在以下位置查看有关本机 Python 模拟库的文档: https://docs.python.org/3/library/unittest.mock.html

    或者,对于 Python 2: https://pypi.python.org/pypi/mock

    【讨论】:

    • 当时我想要的似乎不可能。目标不是模拟 pymysql,因为我想测试代码是否适用于“真正的”SQL 数据库。它是否具有 MySQL 的所有特性并不重要,但它应该能够通过 pymysql 进行通信。在我运行测试的每台机器上本地安装 MySQL 服务器是不切实际的。
    • SQLite 一个“真正的”数据库,而 pymysql 和 MySQLdb 只是 MySQL 的连接器。
    • 另请注意,您绝不需要在“所有必须运行测试的机器”中拥有 MySQL - 所有机器都可以在一台机器上连接到同一个 MySQL 数据库,给定连接 URL
    • 致未来的读者:这是 Docker 容器的一个用例。它简化了这种类型的集成测试,并且不难找到支持文档。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-10-24
    • 2019-12-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多