гипотеза + юнит-тесты блокировка базы данных sqlite - PullRequest
0 голосов
/ 23 сентября 2018

Я пытаюсь проверить мой класс базы данных.Вот упрощенный пример этого.

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. открыть 1-е соединение
  2. вставить данные
  3. зафиксировать и закрыть соединение
  4. открыть 2-е соединение (после первогобыл закрыт) * ​​1018 *
  5. получить данные, вставленные на шаге 2, с помощью выбора
  6. сравнить данные
  7. подтвердить, если входные и выбранные данные не равны.

Но ... Я не должен получать сообщение о блокировке базы данных, если соединения работают с базой данных по одному, не так ли?У меня была идея, что libs (unittest или гипотеза) используют многопоточность, но я ничего не нашел в документации.

Также я попытался запустить его в обычном for и вставить перечисляемые данные.Работает нормально.

Если я не ошибаюсь, каждый вызов метода commit должен разблокировать базу данных, даже если соединение открыто, но, похоже, этого не произошло.

Может кто-нибудь помочь мне понять, почему яувидеть сообщение "база данных заблокирована"?

Ответы [ 2 ]

0 голосов
/ 08 октября 2018

Объект db на самом деле не запускается __del__ до тех пор, пока не будет собран мусор, на который не следует полагаться в любой конкретный момент времени.Как предложил @DRMacIver, для этого было бы лучше использовать менеджер контекста.

Вы можете убедиться, что это реальная проблема, добавив import gc; gc.collect() в строке после del db.

0 голосов
/ 24 сентября 2018

Я подозреваю, что ваше соединение с базой данных на самом деле не закрыто.В любом случае вам не следует использовать один и тот же файл базы данных между запусками тестов - важно, чтобы тесты гипотез повторялись - поэтому проще всего было бы создать временный файл в ваших тестах и ​​использовать его вместо фиксированного test.db ипосмотрим, исчезнет ли проблема.

В целом, я думаю, что полагаться на вещи, закрывающиеся в del, может быть источником странных ошибок, и я бы рекомендовал использовать явный менеджер контекста или аналогичный.

...