假设+单元测试测试锁定sqlite数据库

时间:2018-09-23 13:08:31

标签: python python-3.x unit-testing python-hypothesis

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

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方法也必须取消阻止数据库,但是似乎没有发生。

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

2 个答案:

答案 0 :(得分:2)

我怀疑您的数据库连接实际上没有关闭。无论如何,您都不应该在两次测试运行之间使用相同的数据库文件-重要的是假设测试应具有可重复性-因此最简单的方法是在测试中创建一个临时文件,并使用该文件代替固定的{{1} },看看问题是否消失了。

更笼统地说,我认为依靠test.db中关闭的内容往往会产生奇怪的错误,我鼓励使用显式的context manager或类似内容。

答案 1 :(得分:1)

firstCol对象直到被垃圾回收后才真正运行db,您不应依赖它在任何特定时间发生。正如@DRMacIver建议的那样,为此最好使用上下文管理器。

您可以通过在__del__之后的行中添加import gc; gc.collect()来检查这是否是真正的问题。