newt
newt

Reputation: 309

MySQLdb Python - test databases

I would like to run some tests for code that uses a MySQL database. Right now, the code consists of multiple modules that all import a common module mainlib. This module does the

db = MySQLdb.connect(host='localhost', user='admin', password='admin', db='MyDatabase'). 

I would like to do tests using a test database instead of the real database.

I was thinking I could close the connection (mainlib.db.close()) and create a new connection in the test script:

db = MySQLdb.connect(host='localhost', user='admin', password='admin', db='TestDatabase')

and name the new cursor with the same global variable. But I am unsure of how the imports in the other modules work. In any case, this method doesn't seem to work, as I get InterfaceError: (0, '') as well as no data back from my test database cursor.

Does anyone know how to switch to a test database without modifying the source code?

Upvotes: 0

Views: 605

Answers (2)

Steve Jessop
Steve Jessop

Reputation: 279255

Python's "global" variables don't have global scope. They are module-scope variables. So the same-named global in different modules isn't the same variable.

I think you might be closing mainlib.db and then setting mytestcode.db to a new database. All the rest of your code of course continues to use mainlib.db, which is now closed.

Try mainlib.db = MySQLdb.connect(...), and the same for the cursor. Directly modifying another module's variables is ugly, but it works as you'd expect.

The alternative would be to introduce a way of configuring how mainlib opens the DB. For example, you could have a function like this in mainlib:

db = None
dbname = None
cursor = None

def connectdb(name = None):
    """
    Set up the global database connection and cursor, if it isn't already.

    Omit 'name' when the caller doesn't care what database is used,
    and is happy to accept whatever database is already connected or
    connect to a default database.

    Since there cannot be multiple global databases, an exception is thrown
    if 'name' is specified, the global connection already exists, and the
    names don't match.
    """
    global db, dbname, cursor
    if db is None:
        if name is None:
            name = 'MyDatabase'
        db = MySQLdb.connect(host='localhost', user='admin', password='admin', db=name)
        dbname = name
        cursor = db.cursor()
    elif name not in (None, dbname):
        raise Exception('cannot connect to the specified db: the global connection already exists and connects to a different db')

Now, in your normal program (not in every module, just the top level) you call mainlib.connectdb() right after importing mainlib. In your test code you call mainlib.connectdb('TestDatabase').

Optionally, you could have connectdb return the cursor and/or the connection object, That way, everything that uses the global db can go through this function.

Personally, I prefer not to use globals for this at all -- I would have a function to create a database connection and I would pass that database as a parameter into anything that needs it. However, I realise that tastes vary in this respect.

Upvotes: 1

ZJS
ZJS

Reputation: 4051

A quick fix would be to use the same cursor, but to be explicit with the database when selecting a table. for instance if you have a table T in both databases.

you could do

select * from myDatabase.T   #if you want to use the real table

or

select * from TestDatabase.T  #if you want to use the test table

Upvotes: 0

Related Questions