1

Suppose I'm following the Flask-SQLAlchemy quickstart example, and I want to add a couple of unittests.

My model might look something like:

db = SQLAlchemy(app)
Base = db.Model

class Account(Base):
    id = Column(Integer, primary_key=True)
    name = Column(String(1000))

For unittesting, I'll want to create and destroy a database for each test.

def _setup_database():
    db_name = 'test_%s' % random.randint(0,999999)

    # (Code that creates database with db_name and setups the schema)

    app.config['DB_NAME'] = db_name
    app.config['SQLALCHEMY_DATABASE_URI'] = 'postgresql:///{}'.format(db_name)


def _destroy_db():
    db_name = app.config['DB_NAME']

    # Code that destroys the test db


class TestAccounts(unittest.TestCase):
    def setUp(self):
        _setup_database()

    def tearDown(self):
        _destroy_db()

    def test_new_signup(self):
        account = models.Account(...)

    def test_something_else(self):
        account = models.Account(...)

The problem here is that, if I run this code in an environment where unittests are multi-threaded, there is a race condition. Two databases are usually setup simultaneously and app.config is pointed to one of them.

If I were using SQLAlchemy directly, I would create a new session for each test and use that session. But Flask-SQLAlchemy creates sessions for me, and as such, seems to depend on having one global app.config['SQLALCHEMY_DATABASE_URI'] to point to a database.

What's the right way to create test databases and point a test thread to them with Flask-SQLAlchemy?

3
  • 1
    Don't have an answer but curious as to why you are doing multithreaded tests? Seems like an unnecessary layer of complexity. Commented Jul 11, 2017 at 0:52
  • @Adam It results in tests getting done a lot faster. Don't most people use multiple threads for unit tests? Commented Jul 11, 2017 at 17:29
  • 1
    I've never done it. My work doesn't have a robust CI/testing regimen in place. Commented Jul 11, 2017 at 20:42

1 Answer 1

3

With unittest TestCase.setUp and TestCase.tearDown are run for each test_ functions.

So running your test in multithreaded process will indeed create a race condition. You need to either run your test in a single thread. Which will fix the race condition, but you'll still create and destroy the all database for each test which is unnecessary and slow.

A better solution is to use the setUpclass and tearDownClass methods, which only run once per test class.

If you need to run this fixtures for all classes in a module there is also setUpModule and tearDownModule.

If you need to set fixtures for the full session now you have a problem... IMHO that is the time to switch to pytest.

Sign up to request clarification or add additional context in comments.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.