1

我正在尝试测试我的数据库类。这是它的简化示例。

class Database:
""" it has more methods but I show only the most important """
    def __init__(self, name):
        # let's think the db-file exists with tables
        self.conn = sqlite3.connect(name)
        self.cursor = self.conn.cursor()

    def __del__(self):
    """ Here I close connection if the object was destroyed """
        self.conn.close()

    def insert(self, col1, col2, col3):
    """ The key method where problem is """
        self.cursor.execute(insert_query.format(col1, col2, col3))
        self.conn.commit()  # here I do commit to apply changes with DB

所以,我想检查insert方法。测试用例类是:

class DatabaseTestCase(unittest.TestCase):
""" it has other methods but the problem is here """
    @given(col1=text(col1_params), col2=text(col2_params), col3=text(col3_params))
    def test_db_insert(self, col1, col2, col3):
        db = Database("test.db")
        input_data = col1, col2, col3

        # insert with commit (see Database example above)
        db.insert(*input_data)

        # delete object and close connection
        del db

        # recreate the object to get sure my data was added and 
        # the changes were commited
        db = Database("test.db")

        # I use the way not to use my own methods of Database object
        cursor = db.conn.execute("SELECT * FROM mytable WHERE col1 = '{}'".format(col1))
        result = cursor.fetchone()

        for input_item, row_item in zip(input_data, result):
            pass  # assert here

        # close connection with deleting of the db object
        del db

db.insert问题是从测试方法调用时回溯中的“数据库被锁定” 。我将代码视为下一步:

  1. 打开第一个连接
  2. 插入数据
  3. 提交并关闭连接
  4. 打开第二个连接(在第一个被关闭之后)
  5. 使用 select 获取在步骤 2 中插入的数据
  6. 比较数据
  7. 如果输入和选择的数据不相等,则断言。

但是...如果连接一个一个地与数据库一起工作,我就不会收到有关数据库阻塞的消息,是吗?我知道库(单元测试或假设)使用线程,但我在文档中一无所获。

我也尝试照常运行它for并插入可枚举的数据。它工作正常。

如果我没有错,commit即使打开连接,每次调用方法都必须解除对数据库的阻塞,但似乎没有发生。

谁能帮我理解为什么我看到“数据库已锁定”消息?

4

2 回答 2

2

我怀疑您的数据库连接实际上并没有被关闭。无论如何,您不应该在测试运行之间使用相同的数据库文件——假设测试是可重复的,这一点很重要——所以最简单的做法是在测试中创建一个临时文件并使用它而不是固定文件test.db,看看是否问题消失了。

更一般地说,我认为依赖封闭的东西del往往会导致奇怪的错误,我会鼓励使用显式上下文管理器或类似的东西。

于 2018-09-24T08:23:19.820 回答
1

db对象在被垃圾收集之前不会真正运行__del__,您不应该依赖于在任何特定时间发生这种情况。正如@DRMacIver 建议的那样,最好为此使用上下文管理器。

您可以通过import gc; gc.collect()del db.

于 2018-10-08T06:39:21.457 回答